home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 26 / Cream of the Crop 26.iso / os2 / pvm34b3.zip / pvm34b3 / pvm3 / src / pvmd.c < prev    next >
Text File  |  1997-08-08  |  104KB  |  4,718 lines

  1.  
  2. static char rcsid[] =
  3.     "$Id: pvmd.c,v 1.29 1997/07/16 21:10:41 pvmsrc Exp $";
  4.  
  5. /*
  6.  *         PVM version 3.4:  Parallel Virtual Machine System
  7.  *               University of Tennessee, Knoxville TN.
  8.  *           Oak Ridge National Laboratory, Oak Ridge TN.
  9.  *                   Emory University, Atlanta GA.
  10.  *      Authors:  J. J. Dongarra, G. E. Fagg, M. Fischer
  11.  *          G. A. Geist, J. A. Kohl, R. J. Manchek, P. Mucci,
  12.  *         P. M. Papadopoulos, S. L. Scott, and V. S. Sunderam
  13.  *                   (C) 1997 All Rights Reserved
  14.  *
  15.  *                              NOTICE
  16.  *
  17.  * Permission to use, copy, modify, and distribute this software and
  18.  * its documentation for any purpose and without fee is hereby granted
  19.  * provided that the above copyright notice appear in all copies and
  20.  * that both the copyright notice and this permission notice appear in
  21.  * supporting documentation.
  22.  *
  23.  * Neither the Institutions (Emory University, Oak Ridge National
  24.  * Laboratory, and University of Tennessee) nor the Authors make any
  25.  * representations about the suitability of this software for any
  26.  * purpose.  This software is provided ``as is'' without express or
  27.  * implied warranty.
  28.  *
  29.  * PVM version 3 was funded in part by the U.S. Department of Energy,
  30.  * the National Science Foundation and the State of Tennessee.
  31.  */
  32.  
  33. /*
  34.  *    pvmd.c
  35.  *
  36.  *    Mr. pvm daemon.
  37.  *
  38. $Log: pvmd.c,v $
  39.  * Revision 1.29  1997/07/16  21:10:41  pvmsrc
  40.  * WIN32 Fixes - Markus.
  41.  *
  42.  * Revision 1.28  1997/07/02  20:27:29  pvmsrc
  43.  *     Fixed startup race on shmem to that a shmem task can get fully
  44.  *     configured before getting any messages.
  45.  *     This involved adding two states
  46.  *     TF_PRESHMCONN and TF_SHM.  TF_PRESHMCONN indicates that messages
  47.  *     with MM_PRIO set can be sent to a task, but regular messages are
  48.  *     queued. This allows shmem tasks to be completely configured
  49.  *     before any messages flow.  When the daemon changes the state from
  50.  *     TF_PRESHMCONN to TF_SHMCONN it calls shm_wrt_pkts to write any
  51.  *     packets that were queued before task state changed to TF_SHMCONN.
  52.  *
  53.  * Revision 1.27  1997/06/27  21:17:17  pvmsrc
  54.  * Using sigset() to force daemon under SUNMP to catch SIGCLD.
  55.  *
  56.  * Revision 1.26  1997/06/27  19:26:09  pvmsrc
  57.  * Integrated WIN32 changes.
  58.  *
  59.  * Revision 1.25  1997/06/24  20:37:56  pvmsrc
  60.  * Installed new env var features:
  61.  *     - PVM_PATH overrides default execution path (but not hostfile ep=).
  62.  *     - PVM_WD overrides default working directory (but not hostfile wd=).
  63.  *
  64.  * Revision 1.24  1997/06/16  13:41:11  pvmsrc
  65.  * forkexec() passes extra info to taskers.
  66.  *
  67.  * Revision 1.23  1997/06/12  20:14:57  pvmsrc
  68.  * Added #define for MAXPATHLEN.
  69.  *     - fix submitted by Brian Forney (bforney@cray.com)
  70.  *         of Cray Research, Inc.
  71.  *
  72.  * Revision 1.22  1997/06/02  13:21:22  pvmsrc
  73.  * Added TM_SHMCONN test in pkt_to_task so that remote tasks write to local
  74.  * tasks via their shared memory instead of the t-d socket.
  75.  *
  76.  * Revision 1.21  1997/05/29  15:14:34  pvmsrc
  77.  * Added IMA_SGIMP64 to the infamous PVM_TIMET #define list.  :-)
  78.  *
  79.  * Revision 1.20  1997/05/27  14:49:25  pvmsrc
  80.  * Added test for shmem and TF_SHMCONN to mesg_to_task():
  81.  *     so that mpp_output is used insted of locloutput when a t-d
  82.  *     socket exists when tasks are connected via shared memory
  83.  *     correctly...
  84.  *
  85.  * Revision 1.19  1997/05/13  13:27:01  pvmsrc
  86.  * Fixed up SGI64 crapola - PVM_TIMET -> time_t.
  87.  *
  88.  * Revision 1.18  1997/05/08  21:06:30  pvmsrc
  89.  *     defined PVM_TIMET to time_t for LINUX and LINUXSPARC
  90.  *     and PVM_TIMET to long for all others  so
  91.  *     that calls to ctime don't generate warnings
  92.  *
  93.  * Revision 1.17  1997/05/07  21:19:19  pvmsrc
  94.  * swapped logic around SOCKLENISINT so that it is now
  95.  * the default path and SOCKLENISUINT is the compile-time
  96.  * selected path.
  97.  *
  98.  * Now, AIX 4.1 will have to remove SOCKLENISUINT from
  99.  * their AIXxxx.def configure files.
  100.  *
  101.  * Revision 1.16  1997/05/07  18:37:10  pvmsrc
  102.  * AIX 3.2 vs 4.1 vs 4.2 problems resolved (I hope)
  103.  * Define oslen as size_t with compile flag SOCKLENISINT
  104.  * for AIX 4.1 to explicitly set to int.
  105.  * To use flag - set in conf/AIX46K.def.
  106.  * Tested with cc and gcc on all 3 OS versions.
  107.  *
  108.  * Revision 1.15  1997/05/05  18:51:16  pvmsrc
  109.  *      Removed Ifdefs so that select timeout was set properly for PGONs.
  110.  *
  111.  * Revision 1.14  1997/05/02  13:50:20  pvmsrc
  112.  *     Support for SP2MPI. call mpp_init() mpp_output()
  113.  *
  114.  * Revision 1.13  1997/04/30  21:26:24  pvmsrc
  115.  * SGI Compiler Warning Cleanup.
  116.  *
  117.  * Revision 1.12  1997/04/21  14:58:25  pvmsrc
  118.  * Changed #ifdefs that checked IMA_RS6K,IMA_SP2MPI & IMA_AIX46K
  119.  *     to see if select.h was needed into single define NEEDSSELECTH.
  120.  *     New archs need to set this in conf/
  121.  *
  122.  * Revision 1.11  1997/04/03  16:13:55  pvmsrc
  123.  * 1) Fixed sequence number rollover bug (apparent only when nopax > 1)
  124.  * 2) Fixed queueing order of output pkts (opq). (apparent when nopax > 1)
  125.  *     Packets could  be queued in reverse order causing the remote daemon
  126.  *     to reorder packets even when there were no transmission errors.
  127.  *
  128.  * Revision 1.10  1997/03/07  14:01:06  pvmsrc
  129.  *     Support for Mpps.
  130.  *
  131.  * Revision 1.9  1997/02/13  15:10:02  pvmsrc
  132.  * Removed unnecessary extern for struct waitc *waitlist.
  133.  *     - now in global.h.
  134.  *
  135.  * Revision 1.8  1997/01/28  19:27:02  pvmsrc
  136.  * New Copyright Notice & Authors.
  137.  *
  138.  * Revision 1.7  1996/11/26  19:18:33  pvmsrc
  139.  * Added code to prevent multiple pvmds for a single user on one machine.
  140.  * Define OVERLOADHOST if want to enable multiple pvmds.
  141.  *
  142.  * Revision 1.6  1996/10/25  13:57:59  pvmsrc
  143.  * Replaced old #includes for protocol headers:
  144.  *     - <pvmsdpro.h>, "ddpro.h", "tdpro.h"
  145.  * With #include of new combined header:
  146.  *     - <pvmproto.h>
  147.  *
  148.  * Revision 1.5  1996/10/24  21:31:36  pvmsrc
  149.  * Moved #include "global.h" to below other #includes for typing.
  150.  * Added #include <pvmtev.h> (to get TEV_* constants).
  151.  * Added decl for storing registered tracer info:
  152.  *     - struct Pvmtracer pvmtracer.
  153.  *     - init to { 0, 0, 0, 0, 0, 0, 0, 0, "" }.
  154.  * Changed comparisons on tp->t_outtid:
  155.  *     - check for > 0, not just non-zero.
  156.  *     - to handle new case where task sets to -1 to deny external collect.
  157.  *
  158.  * Revision 1.4  1996/10/14  19:17:03  pvmsrc
  159.  * Used ARCHFLAG SOCKLENISUINT where socket length is unsigned int
  160.  *
  161.  * Revision 1.3  1996/10/09  21:48:16  pvmsrc
  162.  * Problem:
  163.  * --------
  164.  * The problem was the result of AIX4.2 changing the expected datatype of
  165.  * the XxxxLength parameter in the following system function calls:
  166.  *
  167.  * int bind (Socket, Name, NameLength)
  168.  * int getsockname (Socket, Name, NameLength)
  169.  * int recvfrom (Socket, Buffer, Length, Flags, From, FromLength)
  170.  * int accept (Socket, Address, AddressLength)
  171.  *
  172.  * The compiler warning message generated was:
  173.  *   Function argument assignment between types "unsigned long*" and "int*"
  174.  *   is not allowed.
  175.  *
  176.  * Action:
  177.  * -------
  178.  * In PVM functions where oslen was already declared_
  179.  *     changed declaration from:    int oslen;
  180.  *                   to:    unsigned int oslen;
  181.  *
  182.  * In PVM functions where a local "temporary" variable such as i, j, etc.
  183.  * was used_
  184.  *     added declaration of:        unsigned int oslen;
  185.  *     and then changed to use oslen where necessary.
  186.  *
  187.  * Revision 1.2  1996/09/23  23:27:26  pvmsrc
  188.  * Initial Creation - original pvmd.c.
  189.  *
  190.  * Revision 1.40  1995/11/02  16:29:24  manchek
  191.  * added -t flag for test mode.
  192.  * put back save under packet header in netoutput.
  193.  * refragment in pkt_to_host now handles message header correctly
  194.  *
  195.  * Revision 1.39  1995/09/05  19:22:07  manchek
  196.  * forgot ifdef for SP2MPI
  197.  *
  198.  * Revision 1.38  1995/07/28  20:52:01  manchek
  199.  * missed changing src to pk_src in loclinpkt
  200.  *
  201.  * Revision 1.37  1995/07/28  16:40:59  manchek
  202.  * wrap HASERRORVARS around errno declarations
  203.  *
  204.  * Revision 1.36  1995/07/24  19:52:02  manchek
  205.  * message header no longer part of packet data, goes in pkt struct.
  206.  * socket drivers in {locl,net}{in,out}put must strip and reconstitute headers.
  207.  * no longer need to replicate first fragment of message to send,
  208.  * or to save-under.
  209.  * cleaned up line between loclinput and loclinpkt.
  210.  *
  211.  * Revision 1.35  1995/07/19  21:26:57  manchek
  212.  * use new function pvmnametag instead of [dts]mname
  213.  *
  214.  * Revision 1.34  1995/07/18  17:02:03  manchek
  215.  * added code to generate and check crc on each message (MCHECKSUM)
  216.  *
  217.  * Revision 1.33  1995/07/11  18:56:00  manchek
  218.  * main prints PVMSOCK instead of master_config (after mpp_init)
  219.  *
  220.  * Revision 1.32  1995/07/05  16:20:39  manchek
  221.  * work calls mpp_dredge for zombies if task with zero tid closes socket
  222.  * (possibly a shared memory task exiting)
  223.  *
  224.  * Revision 1.31  1995/07/03  19:16:24  manchek
  225.  * removed POWER4 ifdefs and misc. schmutz
  226.  *
  227.  * Revision 1.30  1995/06/28  15:27:33  manchek
  228.  * pvmbailout doesn't set global bailing_out
  229.  *
  230.  * Revision 1.29  1995/06/16  16:28:35  manchek
  231.  * (CSPP) CINDEX macro defined both in pvmd.c and system include file.
  232.  * can undef CINDEX before we define it for us
  233.  *
  234.  * Revision 1.28  1995/06/02  17:51:44  manchek
  235.  * added code to balance spawn (forks) on CSPP
  236.  *
  237.  * Revision 1.27  1995/05/30  17:46:59  manchek
  238.  * Added ifdefs for SP2MPI arch
  239.  *
  240.  * Revision 1.26  1995/05/17  16:31:57  manchek
  241.  * changed global mytid to pvmmytid.
  242.  * pvmbailout sets global bailing_out (used by shared memory code).
  243.  * use PVMDDEBUG envar to set pvmdebmask at startup.
  244.  * added new debug classes.
  245.  * use FDSETISINT.
  246.  * on LINUX systems, check sendto for ENOMEM.
  247.  *
  248.  * Revision 1.25  1995/02/06  22:40:11  manchek
  249.  * shared memory ports call mpp_setmtu before slave_config
  250.  *
  251.  * Revision 1.24  1995/02/06  18:52:24  manchek
  252.  * added debugging prints for when main select in work fails (solaris)
  253.  *
  254.  * Revision 1.23  1995/02/06  05:01:28  manchek
  255.  * hmm
  256.  *
  257.  * Revision 1.22  1995/02/03  16:45:27  manchek
  258.  * touch up reap - define rus as int if we don't think struct rusage exists
  259.  *
  260.  * Revision 1.21  1995/02/01  21:31:23  manchek
  261.  * added clear_opq_of, called when host is deleted from table or pvmd' exits
  262.  *
  263.  * Revision 1.20  1994/12/20  16:40:35  manchek
  264.  * use O_NONBLOCK for RS6K
  265.  *
  266.  * Revision 1.19  1994/11/08  19:05:07  manchek
  267.  * mpp fix?
  268.  *
  269.  * Revision 1.18  1994/11/08  15:30:51  manchek
  270.  * shared memory cleanup
  271.  *
  272.  * Revision 1.17  1994/10/15  19:27:02  manchek
  273.  * make wrk_fds_init(), use instead of FD_ZERO.
  274.  * don't send FIN|ACK to ourself in bailout.
  275.  * don't clean up task until SIGCHLD if TF_FORKD set.
  276.  * check newhosts when deleting host.
  277.  * cast message tags for comparison as integers.
  278.  * in beprime() call task_init instead of trying to clean up
  279.  *
  280.  * Revision 1.16  1994/09/02  15:48:17  manchek
  281.  * added UXPM ifdef to parallel SUN4SOL2
  282.  *
  283.  * Revision 1.15  1994/09/02  15:27:55  manchek
  284.  * forgot to inc refcount of nth fragment in sendmessage
  285.  *
  286.  * Revision 1.14  1994/07/18  19:21:51  manchek
  287.  * added PDMWAITC.
  288.  * fix to call write() with max 4096 length for RS6K
  289.  *
  290.  * Revision 1.13  1994/06/30  21:36:56  manchek
  291.  * don't check remote sockaddr in netinput() on LINUX
  292.  *
  293.  * Revision 1.12  1994/06/04  21:45:10  manchek
  294.  * added unix domain sockets
  295.  *
  296.  * Revision 1.11  1994/06/03  20:38:22  manchek
  297.  * version 3.3.0
  298.  *
  299.  * Revision 1.10  1993/12/20  15:39:28  manchek
  300.  * patch 6 from wcj
  301.  *
  302.  * Revision 1.9  1993/10/25  20:51:11  manchek
  303.  * make sure pvmd doesn't use 0..2 for sockets, etc. - open /dev/null.
  304.  * added code to change process group/disassoc. from tty (TTYDIS).
  305.  * ping other pvmds also when run state is PVMDHTUPD
  306.  *
  307.  * Revision 1.8  1993/10/12  14:18:37  manchek
  308.  * fixed bug in locloutput() - hung if write() returned 0
  309.  *
  310.  * Revision 1.7  1993/10/04  20:27:42  manchek
  311.  * renamed useruid to pvm_useruid for compat with libpvm
  312.  *
  313.  * Revision 1.6  1993/10/04  19:17:45  manchek
  314.  * on Solaris, sendto() can return ECHILD.  Hahahahahaha!!!
  315.  *
  316.  * Revision 1.5  1993/10/04  19:12:25  manchek
  317.  * hd_txseq wasn't wrapped properly with NEXTSEQNUM
  318.  *
  319.  * Revision 1.4  1993/09/23  20:36:19  manchek
  320.  * fixed broken mca lookup
  321.  *
  322.  * Revision 1.3  1993/09/22  19:14:47  manchek
  323.  * added network resend statistic.
  324.  * removed redundant code in netinpkt() where it finds mca
  325.  *
  326.  * Revision 1.2  1993/09/16  21:45:32  manchek
  327.  * replaced reap() - now uses SYSVSIGNAL and NOWAIT3 macros
  328.  *
  329.  * Revision 1.1  1993/08/30  23:26:50  manchek
  330.  * Initial revision
  331.  *
  332.  */
  333.  
  334. #ifndef WIN32
  335. #include <sys/param.h>
  336. #endif
  337. #ifdef NEEDMENDIAN
  338. #include <machine/endian.h>
  339. #endif
  340. #ifdef NEEDENDIAN
  341. #include <endian.h>
  342. #endif
  343. #ifdef NEEDSENDIAN
  344. #include <sys/endian.h>
  345. #endif
  346. #ifndef WIN32
  347. #include <rpc/types.h>
  348. #include <rpc/xdr.h>
  349. #include <sys/time.h>
  350. #include <sys/wait.h>
  351. #include <sys/socket.h>
  352. #include <sys/signal.h>
  353. #include <netinet/in.h>
  354. #include <netinet/tcp.h>
  355. #include <netdb.h>
  356. #include <pwd.h>
  357. #else 
  358. #include "pvmwin.h"
  359. #include "..\xdr\types.h"
  360. #include "..\xdr\xdr.h"
  361. #include <time.h>
  362. #endif
  363. #ifdef IMA_TITN
  364. #include <bsd/sys/types.h>
  365. #else
  366. #include <sys/types.h>
  367. #ifndef WIN32
  368. #include <sys/ioctl.h>
  369. #endif
  370. #endif
  371. #ifndef    NOWAIT3
  372. #include <sys/resource.h>
  373. #endif
  374. #ifdef NEEDSSELECTH
  375. #include <sys/select.h>
  376. #endif
  377. #include <sys/stat.h>
  378. #ifndef NOUNIXDOM
  379. #include <sys/un.h>
  380. #endif
  381. #include <fcntl.h>
  382. #include <errno.h>
  383. #include <stdio.h>
  384. #include <signal.h>
  385. #include <ctype.h>
  386. /* Must come before local CINDEX macro definition */
  387. #if defined(IMA_CSPP) && defined(BALANCED_SPAWN)
  388. #include <sys/cnx_types.h>
  389. #include <sys/cnx_sysinfo.h>
  390. #include <sys/cnx_pattr.h>
  391. #undef CINDEX
  392. #endif
  393. #ifdef    SYSVSTR
  394. #include <string.h>
  395. #define    CINDEX(s,c)    strchr(s,c)
  396. #else
  397. #include <strings.h>
  398. #define    CINDEX(s,c)    index(s,c)
  399. #endif
  400.  
  401. #include <pvm3.h>
  402. #include <pvmproto.h>
  403. #include "pvmalloc.h"
  404. #include "host.h"
  405. #include "pvmdabuf.h"
  406. #include "pvmfrag.h"
  407. #include "pmsg.h"
  408. #include "pkt.h"
  409. #include "task.h"
  410. #include "waitc.h"
  411. #include "listmac.h"
  412. #include "tvdefs.h"
  413. #if defined(IMA_PGON) || defined(IMA_I860) || defined(IMA_CM5) || defined(SHMEM) || defined(IMA_SP2MPI)
  414. #include "pvmdmp.h"
  415. #endif
  416. #include "bfunc.h"
  417. #include <pvmtev.h>
  418. #include "global.h"
  419.  
  420. #ifdef IMA_CRAY
  421. #define MAXPATHLEN PATH_MAX+1
  422. #endif
  423.  
  424. #ifndef    max
  425. #define    max(a,b)    ((a)>(b)?(a):(b))
  426. #endif
  427.  
  428. #ifndef    min
  429. #define    min(a,b)    ((a)<(b)?(a):(b))
  430. #endif
  431.  
  432. #ifndef    TTYDIS
  433. #define    TTYDIS    0
  434. #endif
  435.  
  436. #ifndef    SOMAXCONN
  437. #define    SOMAXCONN    5
  438. #endif
  439.  
  440. #ifdef    NOTMPNAM
  441. #define    TMPNAMFUN(x)    pvmtmpnam(x)
  442. #define    LEN_OF_TMP_NAM    64
  443. char *pvmtmpnam();
  444.  
  445. #else    /*NOTMPNAM*/
  446. #define    TMPNAMFUN(x)    tmpnam(x)
  447. #ifdef    L_tmpnam
  448. #define    LEN_OF_TMP_NAM    L_tmpnam
  449. #else
  450. #define    LEN_OF_TMP_NAM    64
  451. #endif
  452. #endif    /*NOTMPNAM*/
  453.  
  454. #ifdef    STATISTICS
  455. struct statistics {
  456.     int selneg, selzer, selrdy;        /* neg, zero, ready selects */
  457.     int rdneg, rdzer, rdok;            /* neg, zero, positive reads */
  458.     int wrneg, wrzer, wrshr, wrok;    /* neg, zero, short, ok writes */
  459.     int sdneg, sdok;                /* neg, ok sendtos */
  460.     int rfok;                        /* ok recvfroms */
  461.     int refrag;                        /* refragmented frags */
  462.     int netret;                        /* network resends */
  463. };
  464.  
  465. struct statistics stats;
  466. #endif
  467.  
  468. struct deaddata {
  469.     int dd_pid;                /* process id */
  470.     int dd_es;                /* unix exit status */
  471.     struct timeval dd_ut;    /* user time used */
  472.     struct timeval dd_st;    /* system time used */
  473. };
  474.  
  475. void catch();
  476. char *debug_flags();
  477. char *pvmnametag();
  478. void biteme();
  479. void evilsig();
  480. char *getenv();
  481. char *inadport_decimal();
  482. char *inadport_hex();
  483. void pvmbailout();
  484. char *pvmdsockfile();
  485. char *pvmgethome();
  486. char *pvmgetroot();
  487. void reap();
  488. void i_dump();
  489. void hex_inadport __ProtoGlarp__ (( char *, struct sockaddr_in * ));
  490. void mesg_rewind __ProtoGlarp__ (( struct pmsg * ));
  491.  
  492. #if defined(IMA_LINUX) || defined(IMA_LINUXSPARC) || defined(IMA_SGI64) || defined(IMA_SGIMP64)
  493. #define PVM_TIMET time_t
  494. #else
  495. #define PVM_TIMET long
  496. #endif
  497.  
  498. #if defined(IMA_PGON) && !defined(IMA_MPP)
  499. #define IMA_MPP
  500. #endif
  501.  
  502. /***************
  503.  **  Globals  **
  504.  **           **
  505.  ***************/
  506.  
  507. #ifndef HASERRORVARS
  508. extern int errno;
  509. #endif
  510.  
  511. extern struct task *locltasks;    /* from task.c */
  512. extern int log_fd;                /* from logging.c */
  513.  
  514. char **epaths = 0;                /* exec search path */
  515. char *debugger = 0;                /* debugger executable */
  516. int pvmdebmask = 0;                /* which debugging info */
  517. struct htab *filehosts = 0;        /* advisory host table from hostfile */
  518. struct htab *hosts = 0;            /* active host table */
  519. int hostertid = 0;                /* slave pvmd starter task */
  520. char *loclsnam = 0;                /* t-d socket or addr file path */
  521. int loclsock = -1;                /* pvmd-task master tcp socket */
  522. #ifndef NOUNIXDOM
  523. char *loclspath = 0;            /* t-d socket path */
  524. #endif
  525. char *myarchname = ARCHCLASS;
  526. int myhostpart = 0;                /* host number shifted to tid host field */
  527. int pvmfrgsiz = UDPMAXLEN;        /* message frag length (to pack) */
  528. int pvmmydsig = 0;                /* host native data enc */
  529. int pvmmytid = 0;                /* this pvmd tid */
  530. int pvmmyupid = -1;                /* pvmd pid */
  531. int netsock = -1;                /* host-host udp socket */
  532. int nopax = 1;                    /* number of outstanding pkts on d-d link */
  533. struct htab *newhosts = 0;        /* hosts being added by pvmd' */
  534. struct htab *oldhosts = 0;        /* real host table (for pvmd') */
  535. int pvmudpmtu = UDPMAXLEN;        /* local UDP MTU */
  536. int ppnetsock = -1;                /* pvmd' host-host udp socket */
  537. int pprime = 0;                    /* pvmd' pid for when we're forked */
  538. int runstate = 0;                /* pvmd run state */
  539. int pvmschedtid = 0;            /* scheduler task id */
  540. int taskertid = 0;                /* task starter task */
  541. struct Pvmtracer pvmtracer =    /* task tracer info struct */
  542.     { 0, 0, 0, 0, 0, 0, 0, 0, "" };
  543. int tidhmask = TIDHOST;            /* mask for host field of tids */
  544. int tidlmask = TIDLOCAL;        /* mask for local field of tids */
  545. int pvm_useruid = -1;            /* our uid */
  546. char *username = 0;                /* our loginname */
  547.  
  548. #ifdef WIN32
  549. /* the userid is not available in WIN 32! */
  550. /* some useless binary sid struct */
  551. char *pvmtmpspec=0;
  552. int system_loser_win=FALSE;
  553. int nAlert=SO_SYNCHRONOUS_NONALERT;
  554. int nFileHandle;
  555. WSADATA WSAData;
  556. LPOSVERSIONINFO osinfo=0; 
  557. BOOL os_is_NT=FALSE;
  558. #endif
  559.  
  560. /***************
  561.  **  Private  **
  562.  **           **
  563.  ***************/
  564.  
  565. static int totprobes = 0;
  566. static int altprobe = 100;    /* ratio of mpp_input() to select for pgons */
  567.  
  568. static struct deaddata *deads = 0;    /* circ queue of dead task data */
  569. static int ndead = 0;            /* len of deads */
  570. static struct pkt *opq = 0;        /* outstanding pkt q to all hosts */
  571. static int rdead = 0;            /* read ptr for deads */
  572. static int slavemode = 0;        /* started by master pvmd */
  573. static struct pmsg *addmesg = 0;    /* message to self to add slaves */
  574. static int wdead = 0;            /* write ptr for deads */
  575. static fd_set wrk_rfds;            /* fd_sets for select() in work() */
  576. static fd_set wrk_wfds;
  577. /*
  578. static fd_set wrk_efds;
  579. */
  580. static int wrk_nfds = 0;        /* 1 + highest bit set in fds */
  581.  
  582.  
  583. main(argc, argv)
  584.     int argc;
  585.     char **argv;
  586. {
  587.     int i, j;
  588.     char *name = "";
  589.     struct passwd *pe;
  590.     int testmode = 0;
  591.     struct timeval tnow;
  592.     char buf[128];
  593.  
  594. #ifndef WIN32
  595.     /* make sure 0, 1, 2 are in use */
  596.  
  597.     (void)open("/dev/null", O_RDONLY, 0);
  598.     (void)open("/dev/null", O_RDONLY, 0);
  599.     (void)open("/dev/null", O_RDONLY, 0);
  600. #else
  601.     /* WSAStartup has to be called before any socket command */
  602.     /* can be executed. Why ? Ask Bill   */
  603.  
  604.      if (WSAStartup(0x0101, &WSAData) != 0) {
  605.           printf("\nWSAStartup() failed\n");
  606.           ExitProcess(1);
  607.      }
  608.     setsockopt(INVALID_SOCKET,SOL_SOCKET,SO_OPENTYPE,
  609.             (char *)&nAlert,sizeof(int));
  610.     osinfo=malloc(sizeof(LPOSVERSIONINFO));
  611.     osinfo->dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  612.     GetVersionEx(osinfo);
  613.     os_is_NT= ( osinfo->dwPlatformId == VER_PLATFORM_WIN32_NT);
  614. #endif
  615.  
  616.     {
  617.         char *p;
  618.         if (p = getenv("PVMDDEBUG"))
  619.             pvmdebmask = pvmstrtoi(p);
  620.     }
  621.  
  622. #ifndef WIN32
  623.     if ((pvm_useruid = getuid()) == -1) {
  624.         pvmlogerror("main() can't getuid()\n");
  625.         pvmbailout(0);
  626.     }
  627. #else
  628.     username = MyGetUserName();
  629. #endif
  630.  
  631.     pvmsetlog(3);
  632.  
  633. #ifndef WIN32
  634.     if (pe = getpwuid(pvm_useruid))
  635.         username = STRALLOC(pe->pw_name);
  636.     else
  637.         pvmlogerror("main() can't getpwuid\n");
  638.     endpwent();
  639. #endif
  640.  
  641. #ifdef WIN32
  642.     if ((pvmmyupid = _getpid()) == -1) {
  643.         pvmlogerror("main() can't getpid() %d \n",GetLastError());
  644.         pvmbailout(0);
  645.     }
  646. #else
  647.     if ((pvmmyupid = getpid()) == -1) {
  648.         pvmlogerror("main() can't getpid()\n");
  649.         pvmbailout(0);
  650.     }
  651. #endif
  652.  
  653.     (void)pvmgetroot();        /* fail here if we can't */
  654.  
  655.     sprintf(buf, "PVM_ARCH=%s", myarchname);
  656.     pvmputenv(STRALLOC(buf));
  657.  
  658.     pvmmydsig = pvmgetdsig();
  659.  
  660.     ppi_config(&argc, argv);
  661.  
  662. #if defined(IMA_PGON) || defined(IMA_SP2MPI)
  663.     mpp_init(&argc, argv);
  664. #endif
  665.  
  666.     for (i = j = 1; i < argc; i++) {
  667.         if (argv[i][0] == '-') {
  668.             switch (argv[i][1]) {
  669.  
  670.             case 'd':
  671.                 pvmdebmask = pvmstrtoi(argv[i] + 2);
  672.                 break;
  673.  
  674.             case 'n':
  675.                 name = argv[i] + 2;
  676.                 break;
  677.  
  678.             case 'S':
  679.                 argv[j++] = argv[i];
  680.             case 's':
  681.                 slavemode = 1;
  682.                 break;
  683.  
  684.             case 't':
  685.                 testmode = 1;
  686.                 break;
  687.  
  688. #ifdef WIN32
  689.             case 'u':
  690.                 if (os_is_NT==FALSE) { 
  691.                     /* someone is on win95 ... */
  692.                     argv[i]++;argv[i]++;
  693.                     strcpy(username,argv[i]);
  694.                 }
  695.                 else 
  696.                     if (strcmp(strcat("-u",username),argv[i])) {
  697.                         fprintf(stderr,
  698.                                 "Provided Username(%s) does not match ",
  699.                                 username);
  700.                         fprintf(stderr,"with OS account(%s).\n",
  701.                                 argv[i]);
  702.                         fprintf(stderr,"Wrong rshd ?!\n");
  703.                         exit(1);
  704.                 }
  705.                 break;
  706. #endif
  707.  
  708.             default:
  709.                 argv[j++] = argv[i];
  710.             }
  711.  
  712.         } else {
  713.             argv[j++] = argv[i];
  714.         }
  715.     }
  716.     argc = j;
  717.  
  718.     if (pvmdebmask) {
  719.         pvmlogprintf("version %s\n", PVM_VER);
  720.         pvmlogprintf("ddpro %d tdpro %d\n", DDPROTOCOL, TDPROTOCOL);
  721.         pvmlogprintf("main() debug mask is 0x%x (%s)\n",
  722.                 pvmdebmask, debug_flags(pvmdebmask));
  723.     }
  724.  
  725.     if (!*name) {
  726.         if (gethostname(buf, sizeof(buf)-1) == -1) {
  727.             pvmlogerror("main() can't gethostname()\n");
  728.             pvmbailout(0);
  729.         }
  730.         name = buf;
  731.     }
  732.     if (testmode) {
  733.         gettimeofday(&tnow, (struct timezone*)0);
  734.         pvmlogprintf("version %s ddpro %d tdpro %d sdpro %d\n",
  735.                 PVM_VER, DDPROTOCOL, TDPROTOCOL, SDPROTOCOL);
  736.         pvmlogprintf(ctime((PVM_TIMET *) &tnow.tv_sec));
  737.         for (i = 0; i < argc; i++)
  738.             pvmlogprintf("argv[%d]=\"%s\"\n", i, argv[i]);
  739.         exit(0);
  740.     }
  741.  
  742.     if (slavemode)                    /* slave pvmd */
  743.         slave_config(name, argc, argv);
  744.  
  745.     else                            /* master pvmd */
  746.         master_config(name, argc, argv);
  747.  
  748. #if TTYDIS & 8
  749.     setsid();
  750. #endif
  751. #if TTYDIS & 4
  752.     setpgid(0, 0);
  753. #endif
  754. #if TTYDIS & 2
  755.     setpgrp(0, 0);
  756. #endif
  757. #if TTYDIS & 1
  758.     if ((i = open("/dev/tty", O_RDWR, 0)) != -1) {
  759.         (void)ioctl(i, TIOCNOTTY, 0);
  760.         (void)close(i);
  761.     }
  762. #endif
  763.  
  764.     myhostpart = hosts->ht_local << (ffs(tidhmask) - 1);
  765.     pvmmytid = myhostpart | TIDPVMD;
  766.  
  767.     ndead = 1000;    /* XXX hum, static limit makes this easy to do */
  768.  
  769.     /* deads = TALLOC(ndead, int, "pids"); */
  770.  
  771.     deads = TALLOC(ndead, struct deaddata, "dead");
  772.     BZERO((char*)deads, ndead * sizeof(struct deaddata));
  773.  
  774. #ifndef WIN32
  775.     /* no signaling in win32 because no parent child relation ... :-( */
  776.  
  777. #ifndef IMA_I860 /* this signal interferes with getcube() on I860 */
  778. #ifdef    SYSVSIGNAL
  779.     (void)signal(SIGCLD, reap);
  780. #ifdef IMA_SUNMP
  781.     sigset(SIGCLD, reap);    /* yep we go really want to catch our kids */
  782. #endif 
  783. #else
  784.     (void)signal(SIGCHLD, reap);
  785. #endif    /* SYSVSIGNAL */
  786. #endif /*IMA_I860*/
  787.  
  788. #endif
  789.  
  790.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  791. #ifdef WIN32
  792.         (void)signal(SIGINT, (void*) catch);
  793. #else 
  794.         (void)signal(SIGINT, catch);
  795. #endif
  796.  
  797.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  798. #ifdef WIN32
  799.     (void)signal(SIGTERM, (void *) catch);
  800. #else
  801.     (void)signal(SIGTERM, catch);
  802. #endif
  803.  
  804. #ifndef WIN32
  805.     (void)signal(SIGHUP, SIG_IGN);
  806.     (void)signal(SIGPIPE, SIG_IGN);
  807. #endif
  808.  
  809. #ifndef WIN32
  810.     (void)signal(SIGFPE, evilsig);
  811.     (void)signal(SIGILL, evilsig);
  812. #else
  813.     (void)signal(SIGFPE, (void *)evilsig);
  814.     (void)signal(SIGILL, (void *)evilsig);
  815. #endif
  816.  
  817. #ifdef    SIGBUS
  818.     (void)signal(SIGBUS, evilsig);
  819. #endif
  820.  
  821. #ifndef WIN32
  822.     (void)signal(SIGSEGV, evilsig);
  823. #else
  824.     (void)signal(SIGSEGV, (void *)evilsig);
  825. #endif
  826.  
  827. #ifdef    SIGSYS
  828.     (void)signal(SIGSYS, evilsig);
  829. #endif
  830.  
  831. #ifdef    SIGDANGER
  832.     (void)signal(SIGDANGER, biteme);
  833. #endif
  834.  
  835. #ifdef    STATISTICS
  836.     reset_statistics();
  837. #endif
  838.  
  839.     task_init();
  840.     wait_init(myhostpart, TIDLOCAL);
  841.     mb_init();
  842.     ppi_init();
  843.  
  844.     opq = pk_new(0);
  845.     opq->pk_tlink = opq->pk_trlink = opq;
  846.  
  847.     /* print local socket address on stdout in case someone cares */
  848.  
  849.     if (!slavemode) {
  850.         printf("%s\n", getenv("PVMSOCK"));
  851.         fflush(stdout);
  852.     }
  853.  
  854. /* XXX hack to start slaves automatically */
  855.  
  856.     if (!slavemode && filehosts) {
  857.         struct hostd *hp;
  858.         int hh;
  859.         int n = 0;
  860.  
  861.         for (hh = filehosts->ht_last; hh >= 1; hh--)
  862.             if ((hp = filehosts->ht_hosts[hh]) && !(hp->hd_flag & HF_NOSTART))
  863.                 n++;
  864.         if (n) {
  865.             addmesg = mesg_new(0);
  866.             addmesg->m_tag = DM_ADD;
  867.             pkint(addmesg, n);
  868.             for (hh = 1; hh <= filehosts->ht_last; hh++)
  869.                 if ((hp = filehosts->ht_hosts[hh]) && !(hp->hd_flag & HF_NOSTART))
  870.                     pkstr(addmesg, hp->hd_name);
  871.             addmesg->m_dst = TIDPVMD;
  872.         }
  873.     }
  874.     work();
  875.     pvmbailout(0);        /* not reached */
  876.     exit(0);
  877. }
  878.  
  879.  
  880. static char *ffnames[] = {
  881.     "SOM", "EOM", "DAT", "FIN", "ACK"
  882. };
  883.  
  884. char *
  885. pkt_flags(ff)
  886.     int ff;
  887. {
  888.     static char buf[64];
  889.     int bit, i;
  890.  
  891.     buf[0] = 0;
  892.     for (bit = 1, i = 0; i < sizeof(ffnames)/sizeof(ffnames[0]); i++, bit *= 2)
  893.         if (ff & bit) {
  894.             if (buf[0])
  895.                 strcat(buf, ",");
  896.             strcat(buf, ffnames[i]);
  897.         }
  898.     if (!buf[0])
  899.         strcpy(buf, "0");
  900.     return buf;
  901. }
  902.  
  903.  
  904. void
  905. evilsig(sig)
  906.     int sig;
  907. {
  908.     if (runstate == PVMDISTASK)
  909.         exit(sig);
  910.     (void)signal(SIGILL, SIG_DFL);
  911.     (void)signal(SIGFPE, SIG_DFL);
  912. #ifdef    SIGBUS
  913.     (void)signal(SIGBUS, SIG_DFL);
  914. #endif
  915.     (void)signal(SIGSEGV, SIG_DFL);
  916. #ifdef    SIGSYS
  917.     (void)signal(SIGSYS, SIG_DFL);
  918. #endif
  919.     (void)signal(SIGINT, SIG_DFL);
  920.     (void)signal(SIGTERM, SIG_DFL);
  921. #ifndef WIN32
  922.     (void)signal(SIGHUP, SIG_DFL);
  923.     (void)signal(SIGPIPE, SIG_DFL);
  924. #endif
  925. #ifdef    SYSVSIGNAL
  926.     (void)signal(SIGCLD, SIG_DFL);
  927. #else
  928. #ifndef WIN32
  929.     (void)signal(SIGCHLD, SIG_DFL);
  930. #endif
  931. #endif
  932.     pvmlogprintf("evilsig() caught signal %d\n", sig);
  933.     i_dump(1);
  934. /*
  935.     abort();
  936. */
  937.     pvmbailout(-sig);
  938. }
  939.  
  940.  
  941. void
  942. catch(sig)
  943.     int sig;
  944. {
  945.     if (runstate == PVMDISTASK)
  946.         exit(sig);
  947.     (void)signal(SIGINT, SIG_DFL);
  948.     (void)signal(SIGTERM, SIG_DFL);
  949.     pvmlogprintf("catch() caught signal %d\n", sig);
  950.     pvmbailout(sig);
  951. }
  952.  
  953.  
  954. #ifdef    SIGDANGER
  955. void
  956. biteme(sig)
  957.     int sig;
  958. {
  959.     pvmlogprintf("biteme() caught signal %d and spaced it.\n", sig);
  960.     pvmlogerror("the mad fools, when will they learn?\n");
  961. #ifdef    SYSVSIGNAL
  962.     (void)signal(SIGDANGER, biteme);
  963. #endif
  964. }
  965. #endif    /*SIGDANGER*/
  966.  
  967.  
  968. /*    reap()
  969. *
  970. *    Child process has exited.  Put its pid in the fifo of tasks
  971. *    to be cleaned up (in the work loop).
  972. */
  973.  
  974. void
  975. reap(sig)
  976.     int sig;
  977. {
  978.     int pid;
  979.     int es = 0;
  980.  
  981. #ifndef WIN32
  982.  
  983. #ifndef NOWAIT3
  984. #if defined(RUSAGE_SELF)
  985.     struct rusage rus;
  986. #else
  987.     int rus;
  988. #endif
  989. #endif
  990.  
  991.     sig = sig;
  992.  
  993. #ifdef    NOWAIT3
  994. #ifdef    NOWAITPID
  995.     if ((pid = wait(&es)) > 0)
  996. #else
  997.     while ((pid = waitpid(-1, &es, WNOHANG)) > 0)
  998. #endif
  999. #else    /*NOWAIT3*/
  1000.     while ((pid = wait3(&es, WNOHANG, &rus)) > 0)
  1001. #endif    /*NOWAIT3*/
  1002.  
  1003.     {
  1004. #if !defined(NOWAIT3) && defined(RUSAGE_SELF)
  1005.         deads[wdead].dd_ut = rus.ru_utime;
  1006.         deads[wdead].dd_st = rus.ru_stime;
  1007. #else
  1008.         deads[wdead].dd_ut.tv_sec = 0;
  1009.         deads[wdead].dd_ut.tv_usec = 0;
  1010.         deads[wdead].dd_st.tv_sec = 0;
  1011.         deads[wdead].dd_st.tv_usec = 0;
  1012. #endif
  1013.         deads[wdead].dd_pid = pid;
  1014.         deads[wdead].dd_es = es;
  1015.         if (++wdead >= ndead)
  1016.             wdead = 0;
  1017.     }
  1018.  
  1019. #ifdef    SYSVSIGNAL
  1020.     (void)signal(SIGCLD, reap);
  1021. #endif
  1022.  
  1023. #endif
  1024.  
  1025. }
  1026.  
  1027.  
  1028. /*    pvmbailout()
  1029. *
  1030. *    We're hosed.  Clean up as much as possible and exit.
  1031. */
  1032.  
  1033. void
  1034. pvmbailout(n)
  1035.     int n;
  1036. {
  1037.     struct task *tp;
  1038.  
  1039.     pvmlogprintf("pvmbailout(%d)\n", n);
  1040.  
  1041.     /* sockaddr file */
  1042.  
  1043.     if (loclsnam)
  1044.         (void)unlink(loclsnam);
  1045.  
  1046.     /* kill local tasks */
  1047.  
  1048. #ifdef SHMEM
  1049.     mpp_cleanup();
  1050. #endif
  1051.  
  1052.     if (locltasks)
  1053.         for (tp = locltasks->t_link; tp != locltasks; tp = tp->t_link) {
  1054.             if (tp->t_pid)
  1055. #ifndef WIN32
  1056. #ifdef IMA_OS2
  1057.                 (void)os2_kill(tp->t_pid, SIGTERM);
  1058. #else
  1059.                 (void)kill(tp->t_pid, SIGTERM);
  1060. #endif
  1061. #else
  1062.                 (void)kill(tp->t_pid,tp->t_handle,SIGTERM);
  1063. #endif
  1064.             if (tp->t_authnam)
  1065.                 (void)unlink(tp->t_authnam);
  1066.         }
  1067.  
  1068.     /* shutdown slave pvmds / notify master */
  1069.  
  1070.     if (netsock != -1) {
  1071.         char dummy[DDFRAGHDR];
  1072.         int hh;
  1073.         struct hostd *hp;
  1074.  
  1075.         if (pvmdebmask)
  1076.             pvmlogerror("sending FIN|ACK to all pvmds\n");
  1077.         for (hh = hosts->ht_last; hh >= 1; hh--)
  1078.             if ((hp = hosts->ht_hosts[hh]) && hp->hd_hostpart != myhostpart) {
  1079.                 pvmput32(dummy, hp->hd_hostpart | TIDPVMD);
  1080.                 pvmput32(dummy + 4, myhostpart | TIDPVMD);
  1081.                 pvmput16(dummy + 8, 0);
  1082.                 pvmput16(dummy + 10, 0);
  1083.                 pvmput8(dummy + 12, FFFIN|FFACK);
  1084.                 sendto(netsock, dummy, DDFRAGHDR, 0,
  1085.                         (struct sockaddr*)&hp->hd_sad, sizeof(hp->hd_sad));
  1086.             }
  1087.     }
  1088.  
  1089. #ifndef NOUNIXDOM
  1090.     if (loclspath)
  1091.         (void)unlink(loclspath);
  1092. #endif
  1093.  
  1094.     if (n < 0)
  1095.         abort();
  1096.     exit(n);
  1097. }
  1098.  
  1099.  
  1100. void
  1101. wrk_fds_init()
  1102. {
  1103.     wrk_nfds = 0;
  1104.     FD_ZERO(&wrk_rfds);
  1105.     FD_ZERO(&wrk_wfds);
  1106. /*
  1107.     FD_ZERO(&wrk_efds);
  1108. */
  1109. }
  1110.  
  1111.  
  1112. wrk_fds_add(fd, sets)
  1113.     int fd;                /* the fd */
  1114.     int sets;            /* which sets */
  1115. {
  1116. #ifdef    SANITY
  1117.     if (fd < 0 || fd >= FD_SETSIZE) {
  1118.         pvmlogprintf("wrk_fds_add() bad fd %d\n", fd);
  1119.         return 1;
  1120.     }
  1121. #endif
  1122.     if (sets & 1)
  1123.         FD_SET(fd, &wrk_rfds);
  1124.     if (sets & 2)
  1125.         FD_SET(fd, &wrk_wfds);
  1126. /*
  1127.     if (sets & 4)
  1128.         FD_SET(fd, &wrk_efds);
  1129. */
  1130.  
  1131.     /* if this is new highest, adjust nfds */
  1132.  
  1133.     if (fd >= wrk_nfds)
  1134.         wrk_nfds = fd + 1;
  1135.     return 0;
  1136. }
  1137.  
  1138.  
  1139. wrk_fds_delete(fd, sets)
  1140.     int fd;                /* the fd */
  1141.     int sets;            /* which sets */
  1142. {
  1143. #ifdef    SANITY
  1144.     if (fd < 0 || fd >= FD_SETSIZE) {
  1145.         pvmlogprintf("wrk_fds_delete() bad fd %d\n", fd);
  1146.         return 1;
  1147.     }
  1148. #endif
  1149.     if (sets & 1)
  1150.         FD_CLR(fd, &wrk_rfds);
  1151.     if (sets & 2)
  1152.         FD_CLR(fd, &wrk_wfds);
  1153. /*
  1154.     if (sets & 4)
  1155.         FD_CLR(fd, &wrk_efds);
  1156. */
  1157.  
  1158.     /* if this was highest, may have to adjust nfds to new highest */
  1159.  
  1160.     if (fd + 1 == wrk_nfds)
  1161.         while (wrk_nfds > 0) {
  1162.             wrk_nfds--;
  1163.             if (FD_ISSET(wrk_nfds, &wrk_rfds)
  1164.             || FD_ISSET(wrk_nfds, &wrk_wfds)
  1165. /*
  1166.             || FD_ISSET(wrk_nfds, &wrk_efds)
  1167. */
  1168.             ) {
  1169.                 wrk_nfds++;
  1170.                 break;
  1171.             }
  1172.         }
  1173.     return 0;
  1174. }
  1175.  
  1176.  
  1177. /*    clear_opq_of()
  1178. *
  1179. *    Clear packets dst for host in opq but _not_ in host hd_opq.
  1180. */
  1181.  
  1182. int
  1183. clear_opq_of(tid)
  1184.     int tid;            /* host */
  1185. {
  1186.     struct pkt *pp, *pp2;
  1187.  
  1188.     for (pp = opq->pk_tlink; pp != opq; pp = pp->pk_tlink) {
  1189.         if (pp->pk_dst == tid && !pp->pk_link) {
  1190.             pp2 = pp->pk_trlink;
  1191.             LISTDELETE(pp, pk_tlink, pk_trlink);
  1192.             pk_free(pp);
  1193.             pp = pp2;
  1194.         }
  1195.     }
  1196.     return 0;
  1197. }
  1198.  
  1199.  
  1200. /*    work()
  1201. *
  1202. *    The whole sausage
  1203. */
  1204.  
  1205. work()
  1206. {
  1207.     static int lastpinged = 0;    /* host that got last keepalive message */
  1208.     fd_set rfds, wfds;            /* result of select */
  1209. /*
  1210.     fd_set efds;
  1211. */
  1212.     int nrdy;                    /* number of fds ready after select */
  1213.     struct timeval tbail;        /* time to bail if state = STARTUP */
  1214.     struct timeval tping;        /* time to send next keepalive packet */
  1215.     struct timeval tnow;
  1216.     struct timeval tout;
  1217.     struct pmsg *mp;
  1218.     struct task *tp;
  1219.     struct hostd *hp;
  1220. #if defined(IMA_PGON) || defined(IMA_I860) || defined(SHMEM)
  1221.     int nodemsg = 0;
  1222. #if defined(IMA_PGON)
  1223.     struct timeval tpgon;        /* time to spend in paragon select */
  1224.     double tbpl;                /* time at beginning of probe loop */
  1225.     double toutpl;                /* timeout in the probe loop */
  1226.     int timed_out;
  1227.     extern double dclock();
  1228. #endif
  1229. #endif
  1230. #ifdef    SHMEM
  1231.     int someclosed;
  1232. #endif
  1233.  
  1234.     gettimeofday(&tnow, (struct timezone*)0);
  1235.     if (pvmdebmask || myhostpart) {
  1236.         pvmlogprintf("%s (%s) %s %s\n",
  1237.                 hosts->ht_hosts[hosts->ht_local]->hd_name,
  1238.                 inadport_decimal(&hosts->ht_hosts[hosts->ht_local]->hd_sad),
  1239.                 myarchname,
  1240.                 PVM_VER);
  1241.         pvmlogprintf("ready ");
  1242.         pvmlogprintf(ctime((PVM_TIMET *) &tnow.tv_sec));
  1243.     }
  1244.  
  1245.     /*
  1246.     * remind myself to start those pesky slave pvmds
  1247.     */
  1248.  
  1249.     if (addmesg) {
  1250.         struct pmsg *mp = addmesg;
  1251.  
  1252.         addmesg = 0;
  1253.         sendmessage(mp);
  1254.     }
  1255.  
  1256.     /*
  1257.     * init bail (for PVMDSTARTUP) and ping times
  1258.     */
  1259.  
  1260.     pvmgetclock(&tnow);
  1261.     tout.tv_sec = DDBAILTIME;
  1262.     tout.tv_usec = 0;
  1263.     TVXADDY(&tbail, &tnow, &tout);
  1264.  
  1265.     tout.tv_sec = DDPINGTIME;
  1266.     tout.tv_usec = 0;
  1267.     TVXADDY(&tping, &tnow, &tout);
  1268.  
  1269.     /* init select fd sets */
  1270.  
  1271.     wrk_fds_init();
  1272.  
  1273.     if (loclsock >= 0)
  1274.         wrk_fds_add(loclsock, 1);
  1275.     wrk_fds_add(netsock, 1);
  1276.  
  1277.     for (; ; ) {
  1278.  
  1279.         /*
  1280.         *    clean up after any tasks that we got SIGCHLDs for
  1281.         */
  1282.         while (rdead != wdead) {
  1283.             if (deads[rdead].dd_pid == pprime) {
  1284.                 int cc;
  1285. #ifdef SOCKLENISUINT
  1286.                 size_t oslen;
  1287. #else
  1288.                 int oslen;
  1289. #endif
  1290.                 struct sockaddr_in osad;
  1291.                 struct timeval t;
  1292.                 char buf[DDFRAGHDR];
  1293.  
  1294.                 hostfailentry(hosts->ht_hosts[0]);
  1295.                 clear_opq_of((int)(TIDPVMD | hosts->ht_hosts[0]->hd_hostpart));
  1296.                 pprime = 0;
  1297.  
  1298.                 while (1) {
  1299.                     FD_ZERO(&rfds);
  1300.                     FD_SET(ppnetsock, &rfds);
  1301.                     t.tv_sec = 0;
  1302.                     t.tv_usec = 0;
  1303.                     cc = select(ppnetsock + 1,
  1304. #ifdef    FDSETISINT
  1305.                             (int *)&rfds, (int *)0, (int *)0,
  1306. #else
  1307.                             &rfds, (fd_set *)0, (fd_set *)0,
  1308. #endif
  1309.                             &t);
  1310.                     if (cc == 1) {
  1311.                         oslen = sizeof(osad);
  1312.                         recvfrom(ppnetsock, buf, sizeof(buf),
  1313.                                 0, (struct sockaddr*)&osad, &oslen);
  1314.  
  1315.                     } else if (cc != -1 || errno != EINTR)
  1316.                         break;
  1317.                 }
  1318.  
  1319.             } else {
  1320.                 if (tp = task_findpid(deads[rdead].dd_pid)) {
  1321.  
  1322.         /* check for output one last time
  1323.            XXX this could be cleaner by going through main select again
  1324.            XXX before flushing the task */
  1325.  
  1326.                     tp->t_status = deads[rdead].dd_es;
  1327.                     tp->t_utime = deads[rdead].dd_ut;
  1328.                     tp->t_stime = deads[rdead].dd_st;
  1329.                     while (tp->t_out >= 0) {
  1330.                         fd_set rfds;
  1331.  
  1332.                         FD_ZERO(&rfds);
  1333.                         FD_SET(tp->t_out, &rfds);
  1334.                         TVCLEAR(&tout);
  1335.                         if (select(tp->t_out + 1,
  1336. #ifdef    FDSETISINT
  1337.                                 (int *)&rfds, (int *)0, (int *)0,
  1338. #else
  1339.                                 &rfds, (fd_set *)0, (fd_set *)0,
  1340. #endif
  1341.                                 &tout) == 1)
  1342.                             loclstout(tp);
  1343.  
  1344.                         else
  1345.                             break;
  1346.                     }
  1347. #if defined(IMA_PGON) || defined(IMA_SP2MPI)
  1348.                     mpp_free(tp);
  1349. #endif
  1350.                     task_cleanup(tp);
  1351.                     task_free(tp);
  1352.                 }
  1353.             }
  1354.             if (++rdead >= ndead)
  1355.                 rdead = 0;
  1356.         }
  1357.  
  1358.         netoutput();
  1359.  
  1360.         if (runstate == PVMDHALTING) {
  1361.             pvmlogerror("work() pvmd halting\n");
  1362.             pvmbailout(0);
  1363.         }
  1364.  
  1365.         /* bail if new slave and haven't been configured for too long */
  1366.         pvmgetclock(&tnow);
  1367.         if (runstate == PVMDSTARTUP && TVXLTY(&tbail, &tnow)) {
  1368.             pvmlogerror("work() run = STARTUP, timed out waiting for master\n");
  1369.             pvmbailout(0);
  1370.         }
  1371.  
  1372.         /*
  1373.         * send keepalive message to remote pvmd once in a while
  1374.         */
  1375.         if (TVXLTY(&tping, &tnow)) {
  1376.             if (pvmdebmask & (PDMPACKET|PDMSELECT))
  1377.                 pvmlogerror("work() ping timer\n");
  1378.             if (runstate == PVMDNORMAL || runstate == PVMDHTUPD) {
  1379.                 do {
  1380.                     if (++lastpinged > hosts->ht_last)
  1381.                         lastpinged = 1;
  1382.                 } while (!(hp = hosts->ht_hosts[lastpinged]));
  1383.  
  1384.                 if (hp->hd_hostpart != myhostpart
  1385.                 && hp->hd_txq->pk_link == hp->hd_txq) {
  1386.                     mp = mesg_new(0);
  1387.                     mp->m_tag = DM_NULL;
  1388.                     mp->m_dst = hp->hd_hostpart | TIDPVMD;
  1389.                     sendmessage(mp);
  1390.                 }
  1391.             }
  1392.             tout.tv_sec = DDPINGTIME;
  1393.             tout.tv_usec = 0;
  1394.             TVXADDY(&tping, &tnow, &tout);
  1395.         }
  1396.  
  1397.         /*
  1398.         * figure select timeout
  1399.         */
  1400.  
  1401.         if (opq->pk_tlink == opq)
  1402.             tout = tping;
  1403.         else
  1404.             tout = opq->pk_tlink->pk_rtv;
  1405.  
  1406.         if (TVXLTY(&tout, &tnow)) {
  1407.             TVCLEAR(&tout);
  1408.  
  1409.         } else {
  1410.             TVXSUBY(&tout, &tout, &tnow);
  1411.         }
  1412.  
  1413.         if (pvmdebmask & PDMSELECT) {
  1414.             pvmlogprintf("work() select tout is %d.%06d\n",
  1415.                     tout.tv_sec, tout.tv_usec);
  1416.         }
  1417.  
  1418.  
  1419. #ifdef SHMEM
  1420.         if ((nodemsg = mpp_probe()) == 1) {
  1421.             mpp_input();
  1422.             TVCLEAR(&tout);
  1423.         }
  1424. #endif
  1425.  
  1426.         rfds = wrk_rfds;
  1427.         wfds = wrk_wfds;
  1428. /*
  1429.         efds = wrk_efds;
  1430. */
  1431.         if (pvmdebmask & PDMSELECT) {
  1432.             pvmlogprintf("work() wrk_nfds=%d\n", wrk_nfds);
  1433.             print_fdset("work() rfds=", wrk_nfds, &rfds);
  1434.             print_fdset("work() wfds=", wrk_nfds, &wfds);
  1435.         }
  1436.  
  1437. #if !defined(IMA_PGON) && !defined(IMA_I860)
  1438.  
  1439.         if ((nrdy = select(wrk_nfds,
  1440. #ifdef    FDSETISINT
  1441.                 (int *)&rfds, (int *)&wfds, (int *)0,
  1442. #else
  1443.                 &rfds, &wfds, (fd_set *)0,
  1444. #endif
  1445.                 &tout)) == -1) {
  1446.             if (errno != EINTR) {
  1447.                 pvmlogperror("work() select");
  1448.                 pvmlogprintf(" wrk_nfds=%d\n", wrk_nfds);
  1449.                 print_fdset(" rfds=", wrk_nfds, &wrk_rfds);
  1450.                 print_fdset(" wfds=", wrk_nfds, &wrk_wfds);
  1451.                 pvmlogprintf(" netsock=%d, ppnetsock=%d, loclsock=%d\n",
  1452.                         netsock, ppnetsock, loclsock);
  1453.                 task_dump();
  1454.                 pvmbailout(0);
  1455.             }
  1456.         }
  1457.  
  1458. #else /*IMA_PGON/IMA_I860*/
  1459.  
  1460.         timed_out = 0;
  1461.         toutpl = (double)tout.tv_sec + 1e-6*((double)tout.tv_usec);
  1462.         tbpl = dclock();   /* use the pgon hw clock */
  1463.  
  1464.         if (pvmdebmask & PDMSELECT) {
  1465.             pvmlogprintf(
  1466.                     "work() probe loop timeout is %f dclock is %f\n",
  1467.                     toutpl,tbpl);
  1468.         }
  1469.  
  1470.         do {
  1471.             totprobes++;
  1472.             if ((nodemsg = mpp_input()) > 1) 
  1473.             {
  1474.                 mpp_input();
  1475.                 TVCLEAR(&tpgon);
  1476.  
  1477.             } else {
  1478.                 tout.tv_sec = 0;
  1479.                 tout.tv_usec = TIMEOUT;
  1480.             }
  1481.             rfds = wrk_rfds;
  1482.             wfds = wrk_wfds;
  1483.  
  1484.             nrdy = 0;
  1485.  
  1486.             if (totprobes % altprobe == 0)
  1487.             {
  1488.                 totprobes = 0;
  1489.  
  1490.                 if ((nrdy = select(wrk_nfds,
  1491. #ifdef    FDSETISINT
  1492.                         (int *)&rfds, (int *)&wfds, (int *)0,
  1493. #else
  1494.                         &rfds, &wfds, (fd_set *)0,
  1495. #endif
  1496.                         &tout))
  1497.                 == -1) {
  1498.                     if (errno != EINTR) {
  1499.                         pvmlogperror("work() select");
  1500.                         pvmbailout(0);
  1501.                     }
  1502.                 }
  1503.  
  1504.                 if ( (dclock() - tbpl ) >= toutpl)
  1505.                     timed_out = 1;
  1506.                 else
  1507.                     timed_out = 0;
  1508.                 if (timed_out && pvmdebmask & PDMSELECT)
  1509.                 {
  1510.                     pvmlogprintf(
  1511.                             "work() probe loop timeout, dclock %f\n",
  1512.                             dclock());
  1513.                 }
  1514.             }
  1515.  
  1516.             /* Try to send packets that are still on the mpp output q */ 
  1517.             mpp_output( (struct task *) NULL, (struct pkt *) NULL);
  1518.  
  1519.         } while(!(nrdy || nodemsg || timed_out));
  1520.  
  1521. #endif /*IMA_PGON/IMA_I860*/
  1522.  
  1523. #ifdef    STATISTICS
  1524.         switch (nrdy) {
  1525.         case -1:
  1526.             stats.selneg++;
  1527.             break;
  1528.         case 0:
  1529.             stats.selzer++;
  1530.             break;
  1531.         default:
  1532.             stats.selrdy++;
  1533.             break;
  1534.         }
  1535. #endif
  1536.         if (pvmdebmask & PDMSELECT) {
  1537.             pvmlogprintf("work() SELECT returns %d\n", nrdy);
  1538.         }
  1539.  
  1540.     /*
  1541.     *    check network socket and local master socket for action
  1542.     */
  1543.  
  1544.         if (nrdy > 0) {
  1545.             if (FD_ISSET(netsock, &rfds)) {
  1546.                 nrdy--;
  1547.                 netinput();
  1548.             }
  1549.             if (loclsock >= 0 && FD_ISSET(loclsock, &rfds)) {
  1550.                 nrdy--;
  1551.                 loclconn();
  1552.             }
  1553.         }
  1554.  
  1555.     /*
  1556.     *    check tasks for action
  1557.     */
  1558.  
  1559. #ifdef    SHMEM
  1560.         someclosed = 0;
  1561. #endif
  1562.         if (loclsock >= 0) {
  1563.             for (tp = locltasks->t_link;
  1564.                     nrdy > 0 && tp != locltasks;
  1565.                     tp = tp->t_link) {
  1566.  
  1567.                 if (tp->t_sock >= 0 && FD_ISSET(tp->t_sock, &rfds)) {
  1568.                     FD_CLR(tp->t_sock, &rfds);
  1569.                     nrdy--;
  1570.                     if (loclinput(tp)) {
  1571. #ifdef    SHMEM
  1572.                         if (tp->t_tid == 0)
  1573.                             someclosed++;
  1574. #endif
  1575.                         if (pvmdebmask & PDMTASK) {
  1576.                             pvmlogprintf(
  1577.                                     "work() error reading from t%x, marking dead\n",
  1578.                                     tp->t_tid);
  1579.                         }
  1580.                         if (!(tp->t_flag & TF_FORKD)) {
  1581.                             tp = tp->t_rlink;
  1582.                             task_cleanup(tp->t_link);
  1583.                             task_free(tp->t_link);
  1584.  
  1585.                         } else
  1586.                             wrk_fds_delete(tp->t_sock, 3);
  1587.                         continue;
  1588.                     }
  1589.                 }
  1590.  
  1591.                 if (tp->t_sock >= 0 && FD_ISSET(tp->t_sock, &wfds)) {
  1592.                     FD_CLR(tp->t_sock, &wfds);
  1593.                     nrdy--;
  1594.                     if (locloutput(tp)) {
  1595. #ifdef    SHMEM
  1596.                         if (tp->t_tid == 0)
  1597.                             someclosed++;
  1598. #endif
  1599.                         if (!(tp->t_flag & TF_FORKD)) {
  1600.                             tp = tp->t_rlink;
  1601.                             task_cleanup(tp->t_link);
  1602.                             task_free(tp->t_link);
  1603.  
  1604.                         } else
  1605.                             wrk_fds_delete(tp->t_sock, 3);
  1606.                         continue;
  1607.                     }
  1608.                 }
  1609.  
  1610.                 if (tp->t_out >= 0 && FD_ISSET(tp->t_out, &rfds)) {
  1611.                     FD_CLR(tp->t_out, &rfds);
  1612.                     nrdy--;
  1613.                     loclstout(tp);
  1614.                 }
  1615.             }
  1616.         }
  1617. #if defined(IMA_CM5) || defined(IMA_SP2MPI)
  1618.         mpp_output((struct task *)0, (struct pkt *)0);
  1619. #endif
  1620. #ifdef    SHMEM
  1621.         if (someclosed)
  1622.             mpp_dredge();
  1623. #endif
  1624.     }
  1625. }
  1626.  
  1627.  
  1628. /*    netoutput()
  1629. *
  1630. *    Send packets out the wire to remote pvmds.
  1631. */
  1632.  
  1633. netoutput()
  1634. {
  1635.     struct timeval tnow, tx;
  1636.     struct pkt *pp, *pp2;
  1637.     struct hostd *hp;
  1638.     char *cp;
  1639.     int len;
  1640.     int cc;
  1641.     char dummy[DDFRAGHDR];
  1642.  
  1643. /*
  1644.     len = 0;
  1645.     for (pp = opq->pk_tlink; pp != opq; pp = pp->pk_tlink)
  1646.         len++;
  1647.     pvmlogprintf("netoutput() %d in opq\n", len);
  1648. */
  1649.     if (opq->pk_tlink == opq)
  1650.         return 0;
  1651.  
  1652.     /*
  1653.     * send any pkts whose time has come
  1654.     */
  1655.  
  1656.     pvmgetclock(&tnow);
  1657.  
  1658.     while ((pp = opq->pk_tlink) != opq && TVXLTY(&pp->pk_rtv, &tnow)) {
  1659.  
  1660.     /*
  1661.     * fail if we've tried too hard
  1662.     */
  1663.         hp = pp->pk_hostd;
  1664.         if (pp->pk_nrt >= DDMINRETRIES
  1665.         && pp->pk_rto.tv_sec >= DDMINTIMEOUT) {        /* host is toast */
  1666.             pvmlogprintf(
  1667.                     "netoutput() timed out sending to %s after %d, %d.%06d\n",
  1668.                     hp->hd_name, pp->pk_nrt,
  1669.                     pp->pk_rto.tv_sec, pp->pk_rto.tv_usec);
  1670.             hd_dump(hp);
  1671.             hostfailentry(hp);
  1672.             clear_opq_of((int)(TIDPVMD | hp->hd_hostpart));
  1673.             ht_delete(hosts, hp);
  1674.             if (newhosts)
  1675.                 ht_delete(newhosts, hp);
  1676.             continue;
  1677.         }
  1678.  
  1679.         cp = pp->pk_dat;
  1680.         len = pp->pk_len;
  1681.         if (pp->pk_flag & FFSOM) {
  1682.             cp -= MSGHDRLEN;
  1683.             len += MSGHDRLEN;
  1684.             if (cp < pp->pk_buf) {
  1685.                 pvmlogerror("netoutput() no headroom for message header\n");
  1686.                 return 0;
  1687.             }
  1688.             pvmput32(cp, pp->pk_enc);
  1689.             pvmput32(cp + 4, pp->pk_tag);
  1690.             pvmput32(cp + 8, pp->pk_ctx);
  1691.             pvmput32(cp + 16, pp->pk_wid);
  1692.             pvmput32(cp + 20, pp->pk_crc);
  1693.         }
  1694.         cp -= DDFRAGHDR;
  1695.         len += DDFRAGHDR;
  1696.  
  1697.     /*
  1698.     * save under packet header, because databuf may be shared.
  1699.     * we don't worry about message header, because it's only at the head.
  1700.     */
  1701.         BCOPY(cp, dummy, sizeof(dummy));
  1702.         if (cp < pp->pk_buf) {
  1703.             pvmlogerror("netoutput() no headroom for packet header\n");
  1704.             return 0;
  1705.         }
  1706.  
  1707.         if (pvmdebmask & PDMPACKET) {
  1708.             pvmlogprintf(
  1709.             "netoutput() pkt to %s src t%x dst t%x f %s len %d seq %d ack %d retry %d\n",
  1710.                     hp->hd_name, pp->pk_src, pp->pk_dst, pkt_flags(pp->pk_flag),
  1711.                     pp->pk_len, pp->pk_seq, pp->pk_ack, pp->pk_nrt);
  1712.         }
  1713.         pvmput32(cp, pp->pk_dst);
  1714.         pvmput32(cp + 4, pp->pk_src);
  1715.         pvmput16(cp + 8, pp->pk_seq);
  1716.         pvmput16(cp + 10, pp->pk_ack);
  1717.         pvmput32(cp + 12, 0);            /* to keep purify happy */
  1718.         pvmput8(cp + 12, pp->pk_flag);
  1719. #if 0
  1720.         /* drop (don't send) random packets */
  1721.         if (!(random() & 3)) {
  1722.             pvmlogerror("netoutput() darn, dropped one\n");
  1723.             cc = -1;
  1724.         } else
  1725. #endif
  1726.             if ((cc = sendto(netsock, cp, len, 0,
  1727.                     (struct sockaddr*)&hp->hd_sad, sizeof(hp->hd_sad))) == -1
  1728.             && errno != EINTR
  1729. #ifndef WIN32
  1730.             && errno != ENOBUFS
  1731. #endif
  1732. #ifdef    IMA_LINUX
  1733.             && errno != ENOMEM
  1734. #endif
  1735.             ) {
  1736.                 pvmlogperror("netoutput() sendto");
  1737. #if defined(IMA_SUN4SOL2) || defined(IMA_X86SOL2) || defined(IMA_SUNMP) || defined(IMA_UXPM)
  1738.     /* life, don't talk to me about life... */
  1739.                 if (errno == ECHILD)
  1740.                     pvmlogerror("this message brought to you by solaris\n");
  1741.                 else
  1742. #endif
  1743.                 pvmbailout(0);
  1744.             }
  1745. #ifdef    STATISTICS
  1746.         if (cc == -1)
  1747.             stats.sdneg++;
  1748.         else
  1749.             stats.sdok++;
  1750. #endif
  1751.  
  1752.         BCOPY(dummy, cp, sizeof(dummy));    /* restore under header */
  1753.  
  1754.     /*
  1755.     * set timer for next retry
  1756.     */
  1757.         if (cc != -1) {
  1758.             if ((pp->pk_flag & (FFFIN|FFACK)) == (FFFIN|FFACK)) {
  1759.                 pk_free(pp);
  1760.                 if (hp != hosts->ht_hosts[0]) {
  1761.                     hostfailentry(hp);
  1762.                     clear_opq_of((int)(TIDPVMD | hp->hd_hostpart));
  1763.                     ht_delete(hosts, hp);
  1764.                     if (newhosts)
  1765.                         ht_delete(newhosts, hp);
  1766.                 }
  1767.                 continue;
  1768.             }
  1769.             if (!((pp->pk_flag & FFDAT)
  1770.                     || (pp->pk_flag & (FFFIN|FFACK)) == FFFIN)) {
  1771.                 pk_free(pp);
  1772.                 continue;
  1773.             }
  1774.             if (!TVISSET(&pp->pk_at))
  1775.                 pp->pk_at = tnow;
  1776.             TVXADDY(&pp->pk_rtv, &tnow, &pp->pk_rta);
  1777.             TVXADDY(&pp->pk_rto, &pp->pk_rto, &pp->pk_rta);
  1778. #ifdef    STATISTICS
  1779.             if (pp->pk_nrt)
  1780.                 stats.netret++;
  1781. #endif
  1782.             ++pp->pk_nrt;
  1783.             if (pp->pk_rta.tv_sec < DDMAXRTT) {
  1784.                 TVXADDY(&pp->pk_rta, &pp->pk_rta, &pp->pk_rta);
  1785.             }
  1786.  
  1787.         } else {
  1788.             tx.tv_sec = DDERRRETRY/1000000;
  1789.             tx.tv_usec = DDERRRETRY%1000000;
  1790.             TVXADDY(&pp->pk_rtv, &tnow, &tx);
  1791.             TVXADDY(&pp->pk_rto, &pp->pk_rto, &tx);
  1792.         }
  1793.  
  1794.         /* reinsert packet into opq */
  1795.  
  1796.         LISTDELETE(pp, pk_tlink, pk_trlink);
  1797.         for (pp2 = opq->pk_trlink; pp2 != opq; pp2 = pp2->pk_trlink)
  1798.             if (TVXLTY(&pp2->pk_rtv, &pp->pk_rtv))
  1799.                 break;
  1800.         LISTPUTAFTER(pp2, pp, pk_tlink, pk_trlink);
  1801.     }
  1802.     return 0;
  1803. }
  1804.  
  1805.  
  1806. /*    netinput()
  1807. *
  1808. *    Input from a remote pvmd.
  1809. *    Accept a packet, do protocol stuff then pass pkt to netinpkt().
  1810. */
  1811.  
  1812. int
  1813. netinput()
  1814. {
  1815.     struct sockaddr_in osad;        /* sender's ip addr */
  1816. #ifdef SOCKLENISUINT
  1817.     size_t oslen;
  1818. #else
  1819.     int oslen;
  1820. #endif                        /* sockaddr length */
  1821.     struct timeval tnow;
  1822.     struct pkt *pp, *pp2;
  1823.     struct hostd *hp;
  1824.     char *cp;
  1825.     int sqn;
  1826.     int aqn;
  1827.     int ff;
  1828.     int dst;
  1829.     int src;
  1830.     int hh;
  1831.     int already;
  1832.     struct timeval tdiff;            /* packet rtt */
  1833.     int rttusec;
  1834.  
  1835.     /*
  1836.     * alloc new pkt buffer and read packet
  1837.     */
  1838.  
  1839.     pp = pk_new(pvmudpmtu);
  1840.     if (TDFRAGHDR > DDFRAGHDR)
  1841.         pp->pk_dat += TDFRAGHDR - DDFRAGHDR;
  1842.  
  1843.     oslen = sizeof(osad);
  1844.     if ((pp->pk_len = recvfrom(netsock, pp->pk_dat,
  1845.             pp->pk_max - (pp->pk_dat - pp->pk_buf),
  1846.             0, (struct sockaddr*)&osad, &oslen)) == -1) {
  1847.         if (errno != EINTR)
  1848.             pvmlogperror("netinput() recvfrom(netsock)");
  1849.         goto scrap;
  1850.     }
  1851.  
  1852. #if 0
  1853.     /* drop random packets */
  1854.     if (!(random() & 3)) {
  1855.         pvmlogerror("netinput() oops, dropped one\n");
  1856.         goto scrap;
  1857.     }
  1858. #endif
  1859.  
  1860. #ifdef    STATISTICS
  1861.     stats.rfok++;
  1862. #endif
  1863.  
  1864.     cp = pp->pk_dat;
  1865.     pp->pk_len -= DDFRAGHDR;
  1866.     pp->pk_dat += DDFRAGHDR;
  1867.     dst = pp->pk_dst = pvmget32(cp);
  1868.     src = pp->pk_src = pvmget32(cp + 4);
  1869.     sqn = pp->pk_seq = pvmget16(cp + 8);
  1870.     aqn = pvmget16(cp + 10);
  1871.     ff = pp->pk_flag = pvmget8(cp + 12);
  1872.     if (ff & FFSOM) {
  1873.         if (pp->pk_len < MSGHDRLEN) {
  1874.             pvmlogprintf("netinput() SOM pkt src t%x dst t%x too short\n",
  1875.                     src, dst);
  1876.             goto scrap;
  1877.         }
  1878.         cp += DDFRAGHDR;
  1879.         pp->pk_enc = pvmget32(cp);
  1880.         pp->pk_tag = pvmget32(cp + 4);
  1881.         pp->pk_ctx = pvmget32(cp + 8);
  1882.         pp->pk_wid = pvmget32(cp + 16);
  1883.         pp->pk_crc = pvmget32(cp + 20);
  1884.         pp->pk_len -= MSGHDRLEN;
  1885.         pp->pk_dat += MSGHDRLEN;
  1886.     }
  1887.  
  1888.     /*
  1889.     * make sure it's from where it claims
  1890.     */
  1891.  
  1892.     hh = (src & tidhmask) >> (ffs(tidhmask) - 1);
  1893.     if (hh < 0 || hh > hosts->ht_last || !(hp = hosts->ht_hosts[hh])
  1894. #ifndef IMA_LINUX
  1895.     /*
  1896.     * XXX removing these lines is a hack and reduces security between
  1897.     * XXX pvmds somewhat, but it's the easiest fix for Linux right now.
  1898.     */
  1899.     || (osad.sin_addr.s_addr != hp->hd_sad.sin_addr.s_addr)
  1900.     || (osad.sin_port != hp->hd_sad.sin_port)
  1901. #endif
  1902.     ) {
  1903.         pvmlogprintf("netinput() bogus pkt from %s\n",
  1904.                 inadport_decimal(&osad));
  1905.         goto scrap;
  1906.     }
  1907.  
  1908.     if (pvmdebmask & PDMPACKET) {
  1909.         pvmlogprintf(
  1910.         "netinput() pkt from %s src t%x dst t%x f %s len %d seq %d ack %d\n",
  1911.                 hp->hd_name, src, dst, pkt_flags(ff), pp->pk_len, sqn, aqn);
  1912.     }
  1913.  
  1914.     if ((ff & (FFFIN|FFACK)) == (FFFIN|FFACK)) {
  1915.         if (hh == hosts->ht_master) {
  1916.     /*
  1917.     * FIN|ACK from master means we should bailout
  1918.     */
  1919.             if (runstate == PVMDPRIME) {
  1920.                 if (pvmdebmask & PDMSTARTUP)
  1921.                     pvmlogerror("work() PVMDPRIME halting\n");
  1922.                 exit(0);
  1923.             }
  1924.             pvmlogprintf("netinput() FIN|ACK from master (%s)\n",
  1925.                     hp->hd_name);
  1926.             runstate = PVMDHALTING;
  1927.  
  1928.         } else {
  1929.     /*
  1930.     * FIN|ACK from slave means it croaked
  1931.     */
  1932.             pvmlogprintf("netinput() FIN|ACK from %s\n",
  1933.                     hp->hd_name);
  1934.             hd_dump(hp);
  1935.             hostfailentry(hp);
  1936.             clear_opq_of((int)(TIDPVMD | hp->hd_hostpart));
  1937.             if (hp->hd_hostpart) {
  1938.                 ht_delete(hosts, hp);
  1939.                 if (newhosts)
  1940.                     ht_delete(newhosts, hp);
  1941.             }
  1942.         }
  1943.         goto scrap;
  1944.     }
  1945.  
  1946.     /*
  1947.     * done with outstanding packet covered by this ack
  1948.     */
  1949.  
  1950.     if (ff & FFACK) {
  1951.         for (pp2 = hp->hd_opq->pk_link; pp2 != hp->hd_opq; pp2 = pp2->pk_link)
  1952.             if (pp2->pk_seq == aqn) {
  1953.                 if (pp2->pk_flag & FFDAT) {
  1954.                     if (pp2->pk_nrt == 1) {
  1955.                         pvmgetclock(&tnow);
  1956.  
  1957.                         TVXSUBY(&tdiff, &tnow, &pp2->pk_at);
  1958.                         rttusec = tdiff.tv_sec * 1000000 + tdiff.tv_usec;
  1959.                         if (rttusec < 1)
  1960.                             rttusec = 1000;    /* XXX const */
  1961.                         else
  1962.                             if (rttusec > DDMAXRTT*1000000)
  1963.                                 rttusec = DDMAXRTT*1000000;
  1964.                         rttusec += 3 * (hp->hd_rtt.tv_sec * 1000000 + hp->hd_rtt.tv_usec);
  1965.                         rttusec /= 4;
  1966.                         hp->hd_rtt.tv_sec = rttusec / 1000000;
  1967.                         hp->hd_rtt.tv_usec = rttusec % 1000000;
  1968.                     }
  1969.                 }
  1970.                 if (pp2->pk_flag & FFFIN) {
  1971.                     finack_to_host(hp);
  1972.                 }
  1973.                 hp->hd_nop--;
  1974.                 LISTDELETE(pp2, pk_link, pk_rlink);
  1975.                 pk_free(pp2);
  1976.                 break;
  1977.             }
  1978.     }
  1979.  
  1980.     /*
  1981.     * move another pkt to output q
  1982.     */
  1983.  
  1984. /*
  1985.     if ((hp->hd_opq->pk_link == hp->hd_opq)
  1986. */
  1987.     if (hp->hd_nop < nopax
  1988.     && (hp->hd_txq->pk_link != hp->hd_txq)) {
  1989.         if (pvmdebmask & PDMPACKET) {
  1990.             pvmlogprintf("netinput() pkt to opq\n");
  1991.         }
  1992.         pp2 = hp->hd_txq->pk_link;
  1993.         LISTDELETE(pp2, pk_link, pk_rlink);
  1994.         TVCLEAR(&pp2->pk_rtv);
  1995.         TVXADDY(&pp2->pk_rta, &hp->hd_rtt, &hp->hd_rtt);
  1996.         TVCLEAR(&pp2->pk_rto);
  1997.         TVCLEAR(&pp2->pk_at);
  1998.         pp2->pk_nrt = 0;
  1999.         pp2->pk_hostd = hp;
  2000.         pp2->pk_seq = hp->hd_txseq;
  2001.         hp->hd_txseq = NEXTSEQNUM(hp->hd_txseq);
  2002.         LISTPUTBEFORE(hp->hd_opq, pp2, pk_link, pk_rlink);
  2003.         hp->hd_nop++;
  2004.         LISTPUTBEFORE(opq, pp2, pk_tlink, pk_trlink);
  2005.     }
  2006.  
  2007.     if (!(ff & (FFDAT|FFFIN)))
  2008.         goto scrap;
  2009.  
  2010.     /*
  2011.     * send an ack for the pkt
  2012.     */
  2013.  
  2014.     pp2 = pk_new(DDFRAGHDR);    /* XXX could reref a dummy databuf here */
  2015.     pp2->pk_dat += DDFRAGHDR;
  2016.     pp2->pk_dst = hp->hd_hostpart | TIDPVMD;
  2017.     pp2->pk_src = pvmmytid;
  2018.     pp2->pk_flag = FFACK;
  2019.     TVCLEAR(&pp2->pk_rtv);
  2020.     TVCLEAR(&pp2->pk_rta);
  2021.     TVCLEAR(&pp2->pk_rto);
  2022.     TVCLEAR(&pp2->pk_at);
  2023.     pp2->pk_nrt = 0;
  2024.     pp2->pk_hostd = hp;
  2025.     pp2->pk_seq = 0;
  2026.     pp2->pk_ack = sqn;
  2027.     LISTPUTAFTER(opq, pp2, pk_tlink, pk_trlink);
  2028.  
  2029.     if (!(ff & FFDAT))
  2030.         goto scrap;
  2031.  
  2032.     /*
  2033.     * if we don't have it already, put it in reordering q
  2034.     */
  2035.  
  2036.     pp2 = 0;
  2037.     if (SEQLESSTHAN(sqn, hp->hd_rxseq))
  2038.         already = 1;
  2039.     else {
  2040.         already = 0;
  2041.         for (pp2 = hp->hd_rxq->pk_link; pp2 != hp->hd_rxq; pp2 = pp2->pk_link)
  2042.             if (!SEQLESSTHAN(pp2->pk_seq,sqn)) {
  2043.                 if (pp2->pk_seq == sqn)
  2044.                     already = 1;
  2045.                 break;
  2046.             }
  2047.     }
  2048.     if (already) {
  2049.         if (pvmdebmask & PDMPACKET) {
  2050.             pvmlogprintf("netinput() pkt resent from %s seq %d\n",
  2051.                     hp->hd_name, sqn);
  2052.         }
  2053.         goto scrap;
  2054.     }
  2055.  
  2056.     LISTPUTBEFORE(pp2, pp, pk_link, pk_rlink);
  2057.  
  2058.     /*
  2059.     * accept pkts from reordering q
  2060.     */
  2061.  
  2062.     while (pp = hp->hd_rxq->pk_link,
  2063.             pp != hp->hd_rxq && pp->pk_seq == hp->hd_rxseq) {
  2064.         hp->hd_rxseq = NEXTSEQNUM(hp->hd_rxseq);
  2065.         LISTDELETE(pp, pk_link, pk_rlink);
  2066.         netinpkt(hp, pp);
  2067.     }
  2068.     return 0;
  2069.  
  2070. scrap:
  2071.     if (pp)
  2072.         pk_free(pp);
  2073.     return 0;
  2074. }
  2075.  
  2076.  
  2077. /*    netinpkt()
  2078. *
  2079. *    Consume pkt from network.  It's either for the pvmd and needs to
  2080. *    be reassembled into a message or it's for a local task and needs
  2081. *    to be put on the queue to be sent.
  2082. */
  2083.  
  2084. netinpkt(hp, pp)
  2085.     struct hostd *hp;
  2086.     struct pkt *pp;
  2087. {
  2088.     struct mca *mcap = 0;
  2089.     struct task *tp;
  2090.     struct pmsg *mp;
  2091.     struct frag *fp;
  2092.     struct pkt *pp2;
  2093.     int src = pp->pk_src;
  2094.     int dst = pp->pk_dst;
  2095.     int ff = pp->pk_flag;
  2096.     char *cp;
  2097.     int i;
  2098.     int firstmca = 1;
  2099.  
  2100.     if (pvmdebmask & PDMPACKET) {
  2101.         pvmlogprintf(
  2102.         "netinpkt() pkt from %s src t%x dst t%x f %s len %d\n",
  2103.                 hp->hd_name, src, dst, pkt_flags(ff), pp->pk_len);
  2104.     }
  2105.  
  2106.     /* throw out packet if it's not for us */
  2107.  
  2108.     if (TIDISMCA(dst)) {
  2109.         for (mcap = hp->hd_mcas->mc_link; mcap != hp->hd_mcas;
  2110.                 mcap = mcap->mc_link)
  2111.             if (mcap->mc_tid == dst)
  2112.                 break;
  2113.         if (mcap == hp->hd_mcas)
  2114.             mcap = 0;
  2115.     }
  2116.  
  2117.     if ((dst & tidhmask) != myhostpart && !mcap) {
  2118.         if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2119.             pvmlogprintf(
  2120.                     "netinpkt() pkt from t%x for t%x scrapped (not us)\n",
  2121.                     src, dst);
  2122.         }
  2123.         goto done;
  2124.     }
  2125.  
  2126.     if (mcap) {
  2127.  
  2128.         for (i = mcap->mc_ndst; i-- > 0; ) {
  2129.             dst = mcap->mc_dsts[i];
  2130.             if (tp = task_find(dst)) {        /* to local task */
  2131.                 pp2 = pk_new(0);
  2132.                 pp2->pk_src = src;
  2133.                 pp2->pk_dst = dst;
  2134.                 pp2->pk_flag = ff;
  2135.  
  2136. #if defined(IMA_MPP)
  2137.                 if (firstmca)
  2138.                 {
  2139.                     pp2->pk_flag |= (FFMCA | FFMCAWH);
  2140.                     firstmca = 0;
  2141.                 }
  2142.                 else
  2143.                     pp2->pk_flag |= FFMCA;
  2144. #endif
  2145.                 pp2->pk_enc = pp->pk_enc;
  2146.                 pp2->pk_tag = pp->pk_tag;
  2147.                 pp2->pk_ctx = pp->pk_ctx;
  2148.                 pp2->pk_wid = pp->pk_wid;
  2149.                 pp2->pk_crc = pp->pk_crc;
  2150.                 pp2->pk_buf = pp->pk_buf;
  2151.                 pp2->pk_max = pp->pk_max;
  2152.                 pp2->pk_dat = pp->pk_dat;
  2153.                 pp2->pk_len = pp->pk_len;
  2154.                 da_ref(pp->pk_buf);
  2155.  
  2156.                 pkt_to_task(tp, pp2);
  2157.  
  2158.             } else
  2159.                 if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2160.                     pvmlogprintf(
  2161.                     "netinpkt() mc pkt from t%x for t%x scrapped (no dst)\n",
  2162.                             src, dst);
  2163.                 }
  2164.         }
  2165.  
  2166.         if (ff & FFEOM) {
  2167.             if (pvmdebmask & PDMMESSAGE) {
  2168.                 pvmlogprintf("netinpkt() freed mca %x from t%x\n",
  2169.                         mcap->mc_tid, hp->hd_name);
  2170.             }
  2171.             mca_free(mcap);
  2172.         }
  2173.         goto done;
  2174.     }
  2175.  
  2176.     if ((dst & ~tidhmask) == TIDPVMD) {        /* for pvmd */
  2177.         if (ff & FFSOM) {            /* start of message */
  2178.             if (hp->hd_rxm) {
  2179.                 pvmlogprintf("netinpkt() repeated start pkt from %s\n",
  2180.                         hp->hd_name);
  2181.                 goto done;
  2182.             }
  2183.             hp->hd_rxm = mesg_new(0);
  2184.             hp->hd_rxm->m_enc = pp->pk_enc;
  2185.             hp->hd_rxm->m_tag = pp->pk_tag;
  2186.             hp->hd_rxm->m_ctx = pp->pk_ctx;
  2187.             hp->hd_rxm->m_wid = pp->pk_wid;
  2188.             hp->hd_rxm->m_crc = pp->pk_crc;
  2189.             hp->hd_rxm->m_dst = dst;
  2190.             hp->hd_rxm->m_src = src;
  2191.  
  2192.         } else {                    /* middle or end of message */
  2193.             if (!hp->hd_rxm) {
  2194.                 pvmlogprintf(
  2195.                         "netinpkt() spurious pkt (no message) from %s\n",
  2196.                         hp->hd_name);
  2197.                 goto done;
  2198.             }
  2199.         }
  2200.  
  2201.         fp = fr_new(0);
  2202.         fp->fr_buf = pp->pk_buf;
  2203.         fp->fr_dat = pp->pk_dat;
  2204.         fp->fr_max = pp->pk_max;
  2205.         fp->fr_len = pp->pk_len;
  2206.         da_ref(pp->pk_buf);
  2207.         LISTPUTBEFORE(hp->hd_rxm->m_frag, fp, fr_link, fr_rlink);
  2208.         hp->hd_rxm->m_len += fp->fr_len;
  2209.  
  2210.         if (ff & FFEOM) {        /* end of message */
  2211.             mp = hp->hd_rxm;
  2212.             hp->hd_rxm = 0;
  2213. #ifdef    MCHECKSUM
  2214.             if (mp->m_crc != mesg_crc(mp)) {
  2215.                 pvmlogprintf(
  2216.                         "netinpkt() message from t%x to t%x bad checksum\n",
  2217.                         src, dst);
  2218.     /* XXX must free message? */
  2219.                 goto done;
  2220.             }
  2221. #endif
  2222.             mesg_rewind(mp);
  2223.             if (TIDISTASK(src)) {
  2224.                 if (src == pvmschedtid) {
  2225.                     schentry(mp);
  2226.  
  2227.                 } else
  2228.                     if (pvmdebmask & (PDMMESSAGE|PDMAPPL)) {
  2229.                         pvmlogprintf(
  2230.                         "netinpkt() mesg from t%x to t%x tag %d scrapped\n",
  2231.                                 src, dst, mp->m_tag);
  2232.     /* XXX must free message? */
  2233.                     }
  2234.  
  2235.             } else {
  2236.                 netentry(hp, mp);
  2237.             }
  2238.         }
  2239.  
  2240.     } else {                                /* for a task */
  2241.         if (tp = task_find(dst)) {
  2242.  
  2243. #if defined(IMA_PGON) || defined(IMA_I860)
  2244.             if (TIDISNODE(dst))
  2245.                 mpp_output(tp, pp);
  2246.             else
  2247. #endif
  2248.                 pkt_to_task(tp, pp);
  2249.             pp = 0;
  2250.  
  2251.         } else {
  2252.             if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2253.                 pvmlogprintf(
  2254.                         "netinpkt() pkt from t%x for t%x scrapped (no dst)\n",
  2255.                         src, dst);
  2256.     /* XXX must free message? */
  2257.             }
  2258.             goto done;
  2259.         }
  2260.     }
  2261.  
  2262. done:
  2263.     if (pp)
  2264.         pk_free(pp);
  2265.     return 0;
  2266. }
  2267.  
  2268.  
  2269. /*    loclconn()
  2270. *
  2271. *    Task has attempted to connect.  Accept the new connection and make
  2272. *    a blank context for it.
  2273. */
  2274.  
  2275. loclconn()
  2276. {
  2277.     struct task *tp;            /* new task context */
  2278. #ifdef SOCKLENISUINT
  2279.     size_t oslen;
  2280. #else
  2281.     int oslen;
  2282. #endif
  2283.     int i;
  2284. #ifndef NOUNIXDOM
  2285.     struct sockaddr_un uns;
  2286. #endif
  2287.  
  2288. /*
  2289. #ifdef SHMEM
  2290.      return 0;
  2291.     just getma outa here boy!
  2292. #endif
  2293. */
  2294.  
  2295.     tp = task_new(0);
  2296.  
  2297. #ifdef NOUNIXDOM
  2298.     tp->t_salen = sizeof(tp->t_sad);
  2299.  
  2300.     if ((tp->t_sock = accept(loclsock, (struct sockaddr*)&tp->t_sad,
  2301.             &tp->t_salen)) == -1) {
  2302.         pvmlogperror("loclconn() accept");
  2303.         task_free(tp);
  2304.         tp = 0;
  2305.  
  2306.     } else {
  2307.         if (pvmdebmask & (PDMPACKET|PDMTASK)) {
  2308.             pvmlogprintf("loclconn() accept from %s sock %d\n",
  2309.                     inadport_decimal(&tp->t_sad), tp->t_sock);
  2310.         }
  2311. #ifndef NOSOCKOPT
  2312.         i = 1;
  2313.         if (setsockopt(tp->t_sock, IPPROTO_TCP, TCP_NODELAY,
  2314.                 (char*)&i, sizeof(int)) == -1) {
  2315.             pvmlogperror("loclconn() setsockopt");
  2316.         }
  2317. #endif
  2318.     }
  2319.  
  2320. #else /*NOUNIXDOM*/
  2321.     oslen = sizeof(uns);
  2322.     if ((tp->t_sock = accept(loclsock, (struct sockaddr*)&uns, &oslen)) == -1) {
  2323.         pvmlogperror("loclconn() accept");
  2324.         task_free(tp);
  2325.         tp = 0;
  2326.  
  2327.     } else {
  2328.         if (pvmdebmask & (PDMPACKET|PDMTASK))
  2329.             pvmlogerror("loclconn() accept\n");
  2330.     }
  2331.  
  2332. #endif /*NOUNIXDOM*/
  2333.  
  2334.     if (tp) {
  2335. #ifndef WIN32
  2336.         if ((i = fcntl(tp->t_sock, F_GETFL, 0)) == -1)
  2337.             pvmlogperror("loclconn: fcntl");
  2338.         else {
  2339. #ifdef    IMA_RS6K
  2340.     /* did you ever feel as though your mind had started to erode? */
  2341.             i |= O_NONBLOCK;
  2342. #else    /*IMA_RS6K*/
  2343. #ifdef O_NDELAY
  2344.             i |= O_NDELAY;
  2345. #else
  2346.             i |= FNDELAY;
  2347. #endif
  2348. #endif    /*IMA_RS6K*/
  2349.             (void)fcntl(tp->t_sock, F_SETFL, i);
  2350.         }
  2351. #endif
  2352.         wrk_fds_add(tp->t_sock, 1);
  2353.     }
  2354.  
  2355.     return 0;
  2356. }
  2357.  
  2358.  
  2359. /*    locloutput()
  2360. *
  2361. *    Output to local task.  Sends packets until write() blocks.
  2362. *    Deletes task's bit from wrk_wfds if no more data to send.
  2363. *
  2364. *    Returns 0 if okay, else -1 if unrecoverable error.
  2365. */
  2366.  
  2367. locloutput(tp)
  2368.     struct task *tp;
  2369. {
  2370.     struct pkt *pp;
  2371.     char *cp;
  2372.     int len;
  2373.     int n;
  2374.  
  2375.     while ((pp = tp->t_txq->pk_link)->pk_buf) {
  2376.  
  2377.         if (!pp->pk_cpos || pp->pk_cpos < pp->pk_dat) {
  2378.     /*
  2379.     * prepend frag [message] headers if we'll be writing them.
  2380.     */
  2381.             cp = pp->pk_dat;
  2382.             len = pp->pk_len;
  2383.             if (pp->pk_flag & FFSOM) {
  2384.                 cp -= MSGHDRLEN;
  2385.                 len += MSGHDRLEN;
  2386.                 if (cp < pp->pk_buf) {
  2387.                     pvmlogerror("locloutput() no headroom for message header\n");
  2388.                     return 0;
  2389.                 }
  2390.                 pvmput32(cp, pp->pk_enc);
  2391.                 pvmput32(cp + 4, pp->pk_tag);
  2392.                 pvmput32(cp + 8, pp->pk_ctx);
  2393.                 pvmput32(cp + 16, pp->pk_wid);
  2394.                 pvmput32(cp + 20, pp->pk_crc);
  2395.             }
  2396.             cp -= TDFRAGHDR;
  2397.             if (cp < pp->pk_buf) {
  2398.                 pvmlogerror("locloutput() no headroom for packet header\n");
  2399.                 return 0;
  2400.             }
  2401.             pvmput32(cp, pp->pk_dst);
  2402.             pvmput32(cp + 4, pp->pk_src);
  2403.             pvmput32(cp + 8, len);
  2404.             pvmput32(cp + 12, 0);            /* to keep purify happy */
  2405.             pvmput8(cp + 12, pp->pk_flag & (FFSOM|FFEOM));
  2406.             len += TDFRAGHDR;
  2407.         }
  2408.  
  2409.         if (pp->pk_cpos) {
  2410.             cp = pp->pk_cpos;
  2411.             len = pp->pk_len + (pp->pk_dat - cp);
  2412.  
  2413.         } else {
  2414.             pp->pk_cpos = cp;
  2415.             if (pvmdebmask & PDMPACKET) {
  2416.                 pvmlogprintf(
  2417.                     "locloutput() src t%x dst t%x f %s len %d\n",
  2418.                     pp->pk_src, pp->pk_dst, pkt_flags(pp->pk_flag), len);
  2419.             }
  2420.         }
  2421.  
  2422.     /*
  2423.     * send as much as possible; skip to next packet when all sent
  2424.     */
  2425.  
  2426. #if defined(IMA_RS6K) || defined(IMA_SP2MPI)
  2427.         n = write(tp->t_sock, cp, min(len, 4096));
  2428. #else
  2429. #ifndef WIN32
  2430.         n = write(tp->t_sock, cp, len);
  2431. #else
  2432.          n = win32_write_socket(tp->t_sock,cp,len);
  2433. #endif
  2434. #endif
  2435.  
  2436. #ifdef    STATISTICS
  2437.         if (n == -1)
  2438.             stats.wrneg++;
  2439.         else
  2440.             if (!n)
  2441.                 stats.wrzer++;
  2442.             else
  2443.                 if (n == len)
  2444.                     stats.wrok++;
  2445.                 else
  2446.                     stats.wrshr++;
  2447. #endif
  2448.         if (n == -1) {
  2449.             if (errno != EINTR 
  2450. #ifndef WIN32
  2451.                     && errno != EWOULDBLOCK
  2452.                     && errno != ENOBUFS 
  2453. #endif
  2454.                     && errno != EAGAIN)
  2455.             {
  2456. #ifdef WIN32
  2457.             if (GetLastError() != WSAECONNRESET) {
  2458. #endif
  2459.                 pvmlogperror("locloutput() write");
  2460.                 pvmlogprintf("locloutput() marking t%x dead\n",
  2461.                         tp->t_tid);
  2462. #ifdef WIN32
  2463.             }
  2464. #endif
  2465.                 return -1;
  2466.             }
  2467.             break;
  2468.         }
  2469.  
  2470.         if (n > 0) {
  2471.             if (pvmdebmask & PDMPACKET) {
  2472.                 pvmlogprintf(
  2473.                         "locloutput() src t%x dst t%x wrote %d\n",
  2474.                         pp->pk_src, pp->pk_dst, n);
  2475.             }
  2476.             if ((len - n) > 0) {
  2477.                 pp->pk_cpos += n;
  2478.  
  2479.             } else {
  2480. #if defined(IMA_CM5) || defined(IMA_SP2MPI)
  2481.                 int dst = pp->pk_dst;
  2482. #endif
  2483.                 LISTDELETE(pp, pk_link, pk_rlink);
  2484.                 pk_free(pp);
  2485. #if defined(IMA_CM5) || defined(IMA_SP2MPI)
  2486.                 if (TIDISNODE(dst)) {
  2487.                     struct task *tp2;
  2488.  
  2489.                     /* Expensive! But what else can we do? */
  2490.                     if ((tp2 = task_find(dst)) && (tp2->t_flag & TF_CLOSE)) {
  2491.                         mpp_free(tp2);
  2492.                         /* XXX task_cleanup(tp2); */
  2493.                         task_free(tp2);
  2494.                     }
  2495.                 }
  2496. #endif /*defined(IMA_CM5) || defined(IMA_SP2MPI)*/
  2497.             }
  2498.  
  2499.         } else
  2500.             break;
  2501.     }
  2502.  
  2503.     if (tp->t_txq->pk_link == tp->t_txq) {
  2504.         wrk_fds_delete(tp->t_sock, 2);
  2505.  
  2506.     /* flush context if TF_CLOSE set */
  2507.  
  2508.         if (tp->t_flag & TF_CLOSE)
  2509.             return -1;
  2510.     }
  2511.  
  2512.     return 0;
  2513. }
  2514.  
  2515.  
  2516. /*    loclinput()
  2517. *
  2518. *    Input from a task.
  2519. *    Accept a packet and pass pkt to loclinpkt().
  2520. *    Returns 0 else -1 if error (work() should clean up the task context).
  2521. */
  2522.  
  2523. loclinput(tp)
  2524.     struct task *tp;
  2525. {
  2526.     struct pkt *pp = 0;
  2527.     struct pkt *pp2;
  2528.     int n, m;
  2529.  
  2530. again:
  2531.     /*
  2532.     * if no current packet, start a new one
  2533.     */
  2534.  
  2535.     if (!tp->t_rxp) {
  2536.         tp->t_rxp = pk_new(pvmudpmtu);
  2537. /*
  2538.         tp->t_rxp = pk_new(TDFRAGHDR + 2);
  2539. */
  2540.         if (DDFRAGHDR > TDFRAGHDR)
  2541.             tp->t_rxp->pk_dat += DDFRAGHDR - TDFRAGHDR;
  2542.     }
  2543.     pp = tp->t_rxp;
  2544.  
  2545.     /*
  2546.     * read the fragment header and body separately so we can
  2547.     * make a bigger buffer if needed
  2548.     */
  2549.  
  2550.     n = (pp->pk_len < TDFRAGHDR) ? 0 : pvmget32(pp->pk_dat + 8);
  2551.     n += TDFRAGHDR - pp->pk_len;
  2552.     if (pvmdebmask & PDMPACKET) {
  2553.         pvmlogprintf("loclinput() t%x fr_len=%d fr_dat=+%d n=%d\n",
  2554.                 tp->t_tid, pp->pk_len, pp->pk_dat - pp->pk_buf, n);
  2555.     }
  2556. #ifndef WIN32
  2557.     n = read(tp->t_sock, pp->pk_dat + pp->pk_len, n);
  2558. #else 
  2559.     n = win32_read_socket(tp->t_sock,pp->pk_dat + pp->pk_len,n);
  2560. #endif
  2561.     if (pvmdebmask & PDMPACKET) {
  2562.         if (n >= 0) {
  2563.             pvmlogprintf("loclinput() read=%d\n", n);
  2564.         } else
  2565.             pvmlogperror("loclinput() read");
  2566.     }
  2567.  
  2568. #ifdef    STATISTICS
  2569.         switch (n) {
  2570.         case -1:
  2571.             stats.rdneg++;
  2572.             break;
  2573.         case 0:
  2574.             stats.rdzer++;
  2575.             break;
  2576.         default:
  2577.             stats.rdok++;
  2578.             break;
  2579.         }
  2580. #endif
  2581.     if (n == -1) {
  2582.         if (errno != EINTR
  2583. #ifndef WIN32 
  2584.                 && errno != EWOULDBLOCK 
  2585. #endif
  2586.         ) {
  2587.             pvmlogperror("loclinput() read");
  2588.             pvmlogprintf("loclinput() marking t%x dead\n",
  2589.                     tp->t_tid);
  2590.             return -1;
  2591.         }
  2592.         return 0;
  2593.     }
  2594.     if (!n) {
  2595.         if (pvmdebmask & (PDMPACKET|PDMMESSAGE|PDMTASK)) {
  2596.             pvmlogprintf("loclinput() read EOF from t%x sock %d\n",
  2597.                     tp->t_tid, tp->t_sock);
  2598.         }
  2599.         return -1;
  2600.     }
  2601.  
  2602.     if ((pp->pk_len += n) < TDFRAGHDR)
  2603.         return 0;
  2604.  
  2605.     /*
  2606.     * if we have a complete frag, accept it
  2607.     */
  2608.  
  2609.     m = TDFRAGHDR + pvmget32(pp->pk_dat + 8);
  2610.     if (pp->pk_len == m) {
  2611.         tp->t_rxp = 0;
  2612.         pp->pk_dst = pvmget32(pp->pk_dat);
  2613. #if defined(IMA_PGON) || defined(IMA_I860) || defined(IMA_CM5) || defined(IMA_SP2MPI)
  2614.         pp->pk_src = pvmget32(pp->pk_dat + 4);
  2615. #else
  2616.         pp->pk_src = tp->t_tid;
  2617. #endif
  2618.         pp->pk_flag = pvmget8(pp->pk_dat + 12);
  2619.         pp->pk_len -= TDFRAGHDR;
  2620.         pp->pk_dat += TDFRAGHDR;
  2621.         if (pp->pk_flag & FFSOM) {
  2622.             if (pp->pk_len < MSGHDRLEN) {
  2623.                 pvmlogprintf(
  2624.                         "loclinput() SOM pkt src t%x dst t%x too short\n",
  2625.                         pp->pk_src, pp->pk_dst);
  2626.                 pk_free(pp);
  2627.                 return 0;
  2628.             }
  2629.             pp->pk_enc = pvmget32(pp->pk_dat);
  2630.             pp->pk_tag = pvmget32(pp->pk_dat + 4);
  2631.             pp->pk_ctx = pvmget32(pp->pk_dat + 8);
  2632.             pp->pk_wid = pvmget32(pp->pk_dat + 16);
  2633.             pp->pk_crc = pvmget32(pp->pk_dat + 20);
  2634.             pp->pk_len -= MSGHDRLEN;
  2635.             pp->pk_dat += MSGHDRLEN;
  2636.         }
  2637.         if (loclinpkt(tp, pp))
  2638.             return -1;
  2639.         return 0;
  2640.     }
  2641.  
  2642.     /* realloc buffer if frag won't fit */
  2643.  
  2644.     if (pp->pk_len == TDFRAGHDR) {
  2645.         if (m > pp->pk_max - (pp->pk_dat - pp->pk_buf)) {
  2646.             if (!(tp->t_flag & TF_CONN)) {
  2647.                 pvmlogprintf(
  2648.                     "loclinput() unconnected task sends frag length %d (ha)\n",
  2649.                     m);
  2650.                 return -1;
  2651.             }
  2652.             if (DDFRAGHDR > TDFRAGHDR) {
  2653.                 pp2 = pk_new(m + DDFRAGHDR - TDFRAGHDR);
  2654.                 pp2->pk_dat += DDFRAGHDR - TDFRAGHDR;
  2655.             } else
  2656.                 pp2 = pk_new(m);
  2657.             BCOPY(pp->pk_dat, pp2->pk_dat, TDFRAGHDR);
  2658.             pp2->pk_len = pp->pk_len;
  2659.             pk_free(pp);
  2660.             pp = tp->t_rxp = pp2;
  2661.             if (pvmdebmask & PDMPACKET) {
  2662.                 pvmlogprintf("loclinput() realloc frag max=%d\n", m);
  2663.             }
  2664.         }
  2665.         goto again;
  2666.     }
  2667.  
  2668.     return 0;
  2669. }
  2670.  
  2671.  
  2672. /*    loclinpkt()
  2673. *
  2674. *    Consume pkt from task.
  2675. *    If it's for the pvmd it needs to be reassembled into a message.
  2676. *    If for a local or foreign task it needs to be put on a queue to be sent.
  2677. *    If for a remote pvmd, reassemble as for local then fwd whole message.
  2678. *    Returns 0 else -1 if error (work() should cleanup the
  2679. *    task context).
  2680. */
  2681.  
  2682. loclinpkt(tp, pp)
  2683.     struct task *tp;
  2684.     struct pkt *pp;
  2685. {
  2686.     int dst;            /* pkt dst */
  2687.     int ff;                /* pkt flags */
  2688.     struct pkt *pp2;
  2689.     struct frag *fp;
  2690.     struct pmsg *mp;
  2691.     struct hostd *hp;
  2692.     struct task *tp2;
  2693. #if defined(IMA_CM5) || defined(IMA_SP2MPI)
  2694.     struct task *socktp = tp;    /* owner of the socket */
  2695. #endif
  2696.  
  2697.     dst = pp->pk_dst;
  2698.     ff = pp->pk_flag;
  2699.     if (pvmdebmask & PDMPACKET) {
  2700.         pvmlogprintf(
  2701.                 "loclinpkt() src t%x dst t%x f %s len %d\n",
  2702.                 pp->pk_src, dst, pkt_flags(ff), pp->pk_len);
  2703.     }
  2704.  
  2705. #ifdef IMA_SP2MPI
  2706.     if (pp->pk_src > 0 && !tp->t_tid && (tp2 = task_findpid(pp->pk_src))) {
  2707.         /* connect request from pvmhost */
  2708.         mpp_conn(tp, tp2);
  2709.         pk_free(pp);
  2710.         return -1;
  2711.     }
  2712. #endif
  2713. #if defined(IMA_PGON) || defined(IMA_I860) || defined(IMA_CM5) || defined(IMA_SP2MPI)
  2714.     if (TIDISNODE(pp->pk_src))        /* from a node */
  2715.         if (!(tp = task_find(pp->pk_src))) {
  2716.             pvmlogprintf("loclinpkt() from unknown task t%x\n", pp->pk_src);
  2717.             goto done;
  2718.         }
  2719. #endif    /*defined(IMA_PGON) || defined(IMA_I860) || defined(IMA_CM5) || defined(IMA_SP2MPI)*/
  2720.  
  2721.     /*
  2722.     * if to multicast addr, replicate pkt in each q
  2723.     */
  2724.  
  2725.     if (TIDISMCA(dst) && tp->t_mca && tp->t_mca->mc_tid == dst) {
  2726.  
  2727.         struct mca *mcap = tp->t_mca;
  2728.         int i;
  2729.  
  2730.         for (i = mcap->mc_ndst; i-- > 0; ) {
  2731.             dst = mcap->mc_dsts[i];
  2732.             if (hp = tidtohost(hosts, dst)) {
  2733.                 pp2 = pk_new(0);
  2734.                 pp2->pk_src = pp->pk_src;
  2735.                 pp2->pk_dst = mcap->mc_tid;
  2736.                 pp2->pk_flag = ff;
  2737.                 pp2->pk_enc = pp->pk_enc;
  2738.                 pp2->pk_tag = pp->pk_tag;
  2739.                 pp2->pk_ctx = pp->pk_ctx;
  2740.                 pp2->pk_wid = pp->pk_wid;
  2741.                 pp2->pk_crc = pp->pk_crc;
  2742.                 pp2->pk_buf = pp->pk_buf;
  2743.                 pp2->pk_max = pp->pk_max;
  2744.                 pp2->pk_dat = pp->pk_dat;
  2745.                 pp2->pk_len = pp->pk_len;
  2746.                 da_ref(pp->pk_buf);
  2747.  
  2748.                 if (hp->hd_hostpart == myhostpart) {
  2749.                     netinpkt(hp, pp2);
  2750.  
  2751.                 } else {
  2752.                     pkt_to_host(hp, pp2);
  2753.                 }
  2754.  
  2755.             } else
  2756.                 if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2757.                     pvmlogprintf(
  2758.                     "loclinpkt() pkt src t%x dst t%x scrapped (no such host)\n",
  2759.                             pp->pk_src, dst);
  2760.                 }
  2761.         }
  2762.  
  2763.     /* free mca on last pkt */
  2764.  
  2765.         if (ff & FFEOM) {
  2766.             if (pvmdebmask & PDMMESSAGE) {
  2767.                 pvmlogprintf("loclinpkt() freed mca %x for t%x\n",
  2768.                         mcap->mc_tid, tp->t_tid);
  2769.             }
  2770.             mca_free(mcap);
  2771.             tp->t_mca = 0;
  2772.         }
  2773.         goto done;
  2774.     }
  2775.  
  2776.     /*
  2777.     * if to a pvmd, always reassemble (forward if not for us)
  2778.     */
  2779.  
  2780.     if ((dst & ~tidhmask) == TIDPVMD) {
  2781.         if (ff & FFSOM) {            /* start of message */
  2782.             if (tp->t_rxm) {
  2783.                 pvmlogprintf("loclinpkt() repeated start pkt t%x\n",
  2784.                         tp->t_tid);
  2785.                 goto done;
  2786.             }
  2787.             tp->t_rxm = mesg_new(0);
  2788.             tp->t_rxm->m_ctx = pp->pk_ctx;
  2789.             tp->t_rxm->m_tag = pp->pk_tag;
  2790.             tp->t_rxm->m_enc = pp->pk_enc;
  2791.             tp->t_rxm->m_wid = pp->pk_wid;
  2792.             tp->t_rxm->m_crc = pp->pk_crc;
  2793.             tp->t_rxm->m_dst = dst;
  2794.             tp->t_rxm->m_src = tp->t_tid;
  2795.  
  2796.         } else {                    /* middle or end of message */
  2797.             if (!tp->t_rxm) {
  2798.                 pvmlogprintf(
  2799.                     "loclinpkt() pkt with no message src t%x\n",
  2800.                     tp->t_tid);
  2801.                 goto done;
  2802.             }
  2803.         }
  2804.  
  2805.         fp = fr_new(0);
  2806.         fp->fr_buf = pp->pk_buf;
  2807.         fp->fr_dat = pp->pk_dat;
  2808.         fp->fr_max = pp->pk_max;
  2809.         fp->fr_len = pp->pk_len;
  2810.         da_ref(pp->pk_buf);
  2811.  
  2812.         LISTPUTBEFORE(tp->t_rxm->m_frag, fp, fr_link, fr_rlink);
  2813.         tp->t_rxm->m_len += fp->fr_len;
  2814.  
  2815.         if (ff & FFEOM) {        /* end of message */
  2816.             mp = tp->t_rxm;
  2817.             tp->t_rxm = 0;
  2818. #ifdef    MCHECKSUM
  2819.             if (mp->m_crc != mesg_crc(mp)) {
  2820.                 pvmlogprintf(
  2821.                         "loclinpkt() message src t%x dst t%x bad checksum\n",
  2822.                         mp->m_src, dst);
  2823.                 goto done;
  2824.             }
  2825. #endif
  2826.             if (!(dst & tidhmask) || (dst & tidhmask) == myhostpart) {    /* local */
  2827.                 mesg_rewind(mp);
  2828.                 if (mp->m_tag >= (int)SM_FIRST && mp->m_tag <= (int)SM_LAST
  2829.                 && (mp->m_src == pvmschedtid || mp->m_src == hostertid || mp->m_src == taskertid))
  2830.                 {
  2831.                     schentry(mp);
  2832.  
  2833.                 } else {
  2834.                     loclentry(tp, mp);
  2835.                 }
  2836.  
  2837.             } else {        /* remote */
  2838.                 if (!tp->t_tid) {
  2839.                     pvmlogprintf("loclinpkt() pkt src null dst t%x\n", dst);
  2840.                     goto done;
  2841.                 }
  2842.                 sendmessage(mp);
  2843.             }
  2844.     /*
  2845.     * if sock is -1, tm_conn2() wants us to throw out this context
  2846.     * because it's been merged into another.
  2847.     */
  2848. #if defined(IMA_CM5) || defined(IMA_SP2MPI)
  2849.             /* node procs have no socket; they use pvmhost's */
  2850.             if (socktp->t_sock == -1)
  2851. #else
  2852.             if (tp->t_sock == -1)
  2853. #endif
  2854.             {
  2855.                 pk_free(pp);
  2856.                 return -1;
  2857.             }
  2858.         }
  2859.         goto done;
  2860.     }
  2861.  
  2862.     /*
  2863.     * if to a task, put in local or remote send queue
  2864.     */
  2865.  
  2866.     if (TIDISTASK(dst)) {
  2867.         if (!tp->t_tid) {
  2868.             pvmlogprintf("loclinpkt() pkt src null dst t%x\n", dst);
  2869.             goto done;
  2870.         }
  2871.         if ((dst & tidhmask) == myhostpart) {    /* local host */
  2872.             if (tp2 = task_find(dst)) {
  2873.  
  2874. #if defined(IMA_PGON) || defined(IMA_I860)
  2875.                 if (TIDISNODE(dst))
  2876.                     mpp_output(tp2, pp);
  2877.                 else
  2878. #endif
  2879.                     pkt_to_task(tp2, pp);
  2880. /*
  2881.                 LISTPUTBEFORE(tp2->t_txq, pp, pk_link, pk_rlink);
  2882. */
  2883.                 pp = 0;
  2884.  
  2885.             } else
  2886.                 if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2887.                     pvmlogprintf(
  2888.                     "loclinpkt() pkt src t%x dst t%x scrapped (no such task)\n",
  2889.                             pp->pk_src, dst);
  2890.                 }
  2891.  
  2892.         } else {                                /* remote host */
  2893.             if (hp = tidtohost(hosts, dst)) {
  2894.                 pkt_to_host(hp, pp);
  2895.                 pp = 0;
  2896.  
  2897.             } else {
  2898.                 if (pvmdebmask & (PDMPACKET|PDMAPPL)) {
  2899.                     pvmlogprintf(
  2900.                     "loclinpkt() pkt src t%x dst t%x scrapped (no such host)\n",
  2901.                             pp->pk_src, dst);
  2902.                 }
  2903.                 goto done;
  2904.             }
  2905.         }
  2906.     }
  2907.  
  2908. done:
  2909.     if (pp)
  2910.         pk_free(pp);
  2911.  
  2912.     return 0;
  2913. }
  2914.  
  2915.  
  2916. /*    loclstout()
  2917. *
  2918. *    Read stdout/err pipe from a task.
  2919. *    Ship it to the output log tid if set, else send it to the master
  2920. *    pvmd to scribble in its log file.
  2921. */
  2922.  
  2923. loclstout(tp)
  2924.     struct task *tp;
  2925. {
  2926.     int n;
  2927.     struct pmsg *mp;
  2928.  
  2929.     static char buf[4000];
  2930.  
  2931. #ifndef WIN32
  2932.     n = read(tp->t_out, buf, sizeof(buf) - 1);
  2933. #else 
  2934.     n = win32_read_socket(tp->t_out,buf, sizeof(buf) -1);
  2935. #endif
  2936.  
  2937.     if (n < 1) {
  2938.         if (n == 0 || (errno != EINTR 
  2939. #ifndef WIN32
  2940.                 && errno != EWOULDBLOCK
  2941. #endif
  2942.             )) {
  2943.             wrk_fds_delete(tp->t_out, 1);
  2944. #ifndef WIN32
  2945.             (void)close(tp->t_out);
  2946. #else
  2947.             (void)_close(tp->t_out);
  2948. #endif
  2949.             tp->t_out = -1;
  2950.             if (tp->t_outtid > 0) {
  2951.                 mp = mesg_new(0);
  2952.                 mp->m_dst = tp->t_outtid;
  2953.                 mp->m_ctx = tp->t_outctx;
  2954.                 mp->m_tag = tp->t_outtag;
  2955.                 pkint(mp, tp->t_tid);
  2956.                 pkint(mp, 0);
  2957.                 sendmessage(mp);
  2958.                 tp->t_outtid = 0;
  2959.             }
  2960.         }
  2961.  
  2962.     } else {
  2963.         mp = mesg_new(0);
  2964.         pkint(mp, tp->t_tid);
  2965.         pkint(mp, n);
  2966.         pkbyte(mp, buf, n);
  2967.         if (tp->t_outtid > 0) {
  2968.             mp->m_dst = tp->t_outtid;
  2969.             mp->m_ctx = tp->t_outctx;
  2970.             mp->m_tag = tp->t_outtag;
  2971.  
  2972.         } else {
  2973.             mp->m_tag = DM_TASKOUT;
  2974.             mp->m_dst = hosts->ht_hosts[hosts->ht_cons]->hd_hostpart | TIDPVMD;
  2975.         }
  2976.         sendmessage(mp);
  2977.     }
  2978.     return 0;
  2979. }
  2980.  
  2981.  
  2982. /*    mesg_to_task()
  2983. *
  2984. *    Append a message to the send queue for a task.
  2985. *
  2986. *    N.B. Message must contain at least one frag or this will honk.
  2987. */
  2988.  
  2989. int
  2990. mesg_to_task(tp, mp)
  2991.     struct task *tp;
  2992.     struct pmsg *mp;
  2993. {
  2994.     struct frag *fp = mp->m_frag->fr_link;
  2995.     struct pkt *pp;
  2996.     int ff = FFSOM;            /* frag flags */
  2997.     int dst = mp->m_dst;
  2998.  
  2999.     if (pvmdebmask & PDMMESSAGE) {
  3000.         pvmlogprintf("mesg_to_task() dst t%x tag %s len %d\n",
  3001.                 dst, pvmnametag(mp->m_tag, (int *)0), mp->m_len);
  3002.     }
  3003.  
  3004.     /* if nothing yet in q, add task's sock to wrk_wfds */
  3005.  
  3006.     if (tp->t_sock >= 0)
  3007.         wrk_fds_add(tp->t_sock, 2);
  3008.  
  3009.     do {
  3010.         pp = pk_new(0);
  3011.         if (ff & FFSOM) {
  3012.             pp->pk_enc = mp->m_enc;
  3013.             pp->pk_tag = mp->m_tag;
  3014.             pp->pk_ctx = mp->m_ctx;
  3015.             pp->pk_wid = mp->m_wid;
  3016. #ifdef    MCHECKSUM
  3017.             pp->pk_crc = mesg_crc(mp);
  3018. #else
  3019.             pp->pk_crc = 0;
  3020. #endif
  3021.         }
  3022.         pp->pk_buf = fp->fr_buf;
  3023.         pp->pk_dat = fp->fr_dat;
  3024.         pp->pk_max = fp->fr_max;
  3025.         pp->pk_len = fp->fr_len;
  3026.         da_ref(pp->pk_buf);
  3027.         if (fp->fr_link == mp->m_frag)
  3028.             ff |= FFEOM;
  3029.         pp->pk_src = TIDPVMD;
  3030.         pp->pk_dst = dst;
  3031.         pp->pk_flag = ff;
  3032.         ff = 0;
  3033. #if defined(IMA_PGON) || defined(IMA_I860)
  3034.         if (TIDISNODE(dst)) {
  3035.             mpp_output(tp, pp);
  3036.             continue;
  3037.         }
  3038. #endif
  3039. #ifdef SHMEM
  3040.         if ((tp->t_sock < 0) && ( (tp->t_flag & TF_SHMCONN) 
  3041.             || ((tp->t_flag & TF_PRESHMCONN) && (mp->m_flag & MM_PRIO)) ) )  
  3042.         {
  3043.             /* If shmem and no d-t socket or fully connected shmem */
  3044.             /* use mpp routine instead of socket one */
  3045.             mpp_output(tp, pp);
  3046.             continue;
  3047.         }
  3048. #endif
  3049.         if (mp->m_flag & MM_PRIO) {
  3050.             LISTPUTAFTER(tp->t_txq, pp, pk_link, pk_rlink);
  3051.         } else {
  3052.             pkt_to_task(tp, pp);
  3053. /*
  3054.             LISTPUTBEFORE(tp->t_txq, pp, pk_link, pk_rlink);
  3055. */
  3056.         }
  3057.     } while ((fp = fp->fr_link) != mp->m_frag);
  3058.  
  3059.     return 0;
  3060. }
  3061.  
  3062.  
  3063. /*    sendmessage()
  3064. *
  3065. *    Send a message.  If it's for a local task or remote host, cut
  3066. *    apart the fragments and queue to be sent.  If it's for the local
  3067. *    pvmd, just call netentry() with the whole message.
  3068. *
  3069. *    N.B. MM_PRIO only works for single-frag messages.
  3070. */
  3071.  
  3072. int
  3073. sendmessage(mp)
  3074.     struct pmsg *mp;
  3075. {
  3076.     struct hostd *hp = 0;
  3077.     struct task *tp;
  3078.     struct frag *fp;
  3079.     struct pkt *pp;
  3080.     int ff = FFSOM;
  3081.     int dst = mp->m_dst;
  3082.  
  3083.     if (!dst) {
  3084.         pvmlogerror("sendmessage() what? to t0\n");
  3085.     }
  3086.  
  3087.     if (pvmdebmask & PDMMESSAGE) {
  3088.         pvmlogprintf("sendmessage() dst t%x ctx %d tag %s len %d\n",
  3089.                 dst, mp->m_ctx, pvmnametag(mp->m_tag, (int *)0), mp->m_len);
  3090.     }
  3091.  
  3092.     /*
  3093.     *    add a frag to empty message to simplify handling
  3094.     */
  3095.  
  3096.     if ((fp = mp->m_frag->fr_link) == mp->m_frag) {
  3097.         fp = fr_new(MAXHDR);
  3098.         fp->fr_dat += MAXHDR;
  3099.         LISTPUTBEFORE(mp->m_frag, fp, fr_link, fr_rlink);
  3100.     }
  3101.  
  3102.     /*
  3103.     *    route message
  3104.     */
  3105.  
  3106.     if (!(dst & tidhmask) || (dst & tidhmask) == myhostpart) {    /* to local */
  3107.  
  3108.         if (TIDISTASK(dst)) {                /* to local task */
  3109.  
  3110.             if (tp = task_find(dst)) {
  3111.                 mesg_to_task(tp, mp);
  3112.  
  3113.             } else
  3114.                 if (pvmdebmask & (PDMMESSAGE|PDMAPPL)) {
  3115.                     pvmlogprintf(
  3116.                             "sendmessage() scrapped, no such task t%x\n",
  3117.                             dst);
  3118.                 }
  3119.  
  3120.         } else {                /* to myself */
  3121.             mp->m_ref++;
  3122.             mesg_rewind(mp);
  3123.             netentry(hosts->ht_hosts[hosts->ht_local], mp);
  3124.         }
  3125.  
  3126.     } else {                    /* to remote */
  3127.  
  3128.     /* lookup host */
  3129.  
  3130.         if (runstate == PVMDHTUPD)
  3131.             hp = tidtohost(newhosts, dst);
  3132.         if (!hp && !(hp = tidtohost(hosts, dst))) {
  3133.             if (pvmdebmask & (PDMMESSAGE|PDMAPPL)) {
  3134.                 pvmlogprintf("sendmessage() scrapped, no such host t%x\n",
  3135.                         dst);
  3136.             }
  3137.             goto bail;
  3138.         }
  3139.  
  3140.     /* packetize frags */
  3141.  
  3142.         do {
  3143.             pp = pk_new(0);
  3144.             if (ff & FFSOM) {
  3145.                 pp->pk_enc = mp->m_enc;
  3146.                 pp->pk_tag = mp->m_tag;
  3147.                 pp->pk_ctx = mp->m_ctx;
  3148.                 pp->pk_wid = mp->m_wid;
  3149. #ifdef    MCHECKSUM
  3150.                 pp->pk_crc = mesg_crc(mp);
  3151. #else
  3152.                 pp->pk_crc = 0;
  3153. #endif
  3154.             }
  3155.             pp->pk_buf = fp->fr_buf;
  3156.             pp->pk_dat = fp->fr_dat;
  3157.             pp->pk_max = fp->fr_max;
  3158.             pp->pk_len = fp->fr_len;
  3159.             da_ref(pp->pk_buf);
  3160.             if (fp->fr_link == mp->m_frag)
  3161.                 ff |= FFEOM;
  3162.             pp->pk_src = mp->m_src;
  3163.             pp->pk_dst = dst;
  3164.             pp->pk_flag = ff;
  3165.             ff = 0;
  3166.             if (mp->m_flag & MM_PRIO) {
  3167.                 if (pvmdebmask & (PDMMESSAGE|PDMAPPL))
  3168.                     pvmlogerror("sendmessage() PRIO message to host? (scrapped)\n");
  3169.  
  3170.             } else {
  3171.                 pkt_to_host(hp, pp);
  3172.             }
  3173.         } while ((fp = fp->fr_link) != mp->m_frag);
  3174.     }
  3175.  
  3176. bail:
  3177.     pmsg_unref(mp);
  3178.     return 0;
  3179. }
  3180.  
  3181.  
  3182. /*    forkexec()
  3183. *
  3184. *    Search directories in epaths for given file.
  3185. *    Clean up any files we opened, fork and exec the named process.
  3186. *    Leave std{out,err} open so the process can whine if it needs to.
  3187. *
  3188. *    Returns 0 if ok (and fills in tpp), else returns PvmNoFile or
  3189. *    PvmOutOfRes
  3190. *
  3191. *    N.B. must be able to use argv[-1].
  3192. */
  3193.  
  3194. #ifndef WIN32
  3195. /* too many ifdefs, WIN 32 gets its own */
  3196.  
  3197. #ifdef IMA_OS2
  3198. #include<process.h>
  3199. static int nextfakepid = 10000000;        /* XXX fix this */
  3200. int *ptr_nfp=&nextfakepid;
  3201. #endif
  3202.  
  3203. int
  3204. forkexec(flags, name, argv, nenv, env, inst, hosttotal, outof, tpp)
  3205.     int flags;                /* exec options */
  3206.     char *name;                /* filename */
  3207.     char **argv;            /* arg list (argv[-1] must be there) */
  3208.     int nenv;                /* num of envars */
  3209.     char **env;                /* envars */
  3210.     int inst;                /* this processes instance */
  3211.     int hosttotal;            /* how many on this host */
  3212.     int outof;                /* how many are being spawned across machine */
  3213.     struct task **tpp;        /* return task context */
  3214. {
  3215.     int tid;                /* task tid */
  3216.     int pid;                /* task pid */
  3217.     int pfd[2];                /* pipe back from task */
  3218.     struct task *tp;        /* new task context */
  3219.     char path[MAXPATHLEN];
  3220.     struct stat sb;
  3221.     char **ep, **eplist;
  3222.     int i;
  3223.     struct pmsg *mp;        /* message to tasker */
  3224.     struct waitc *wp;
  3225.     int ac;
  3226.     int realrunstate;
  3227.     char buf[32];
  3228.  
  3229.     static char *nullep[] = { "", 0 };
  3230. #ifndef IMA_OS2
  3231.     static int nextfakepid = 10000000;        /* XXX fix this */
  3232. #endif
  3233.     if ((tid = tid_new()) < 0) {
  3234.         pvmlogerror("forkexec() out of tids?\n");
  3235.         return PvmOutOfRes;
  3236.     }
  3237.     tp = task_new(tid);
  3238.  
  3239.     /* search for file */
  3240.  
  3241.     eplist = CINDEX(name, '/') ? nullep : epaths;
  3242.  
  3243.     for (ep = eplist; *ep; ep++) {
  3244.         (void)strcpy(path, *ep);
  3245.         if (path[0])
  3246.             (void)strcat(path, "/");
  3247.         (void)strncat(path, name, sizeof(path) - strlen(path) - 1);
  3248. #ifdef IMA_OS2
  3249.                 strcat(path,".exe");  /*  no *.cmd !!! */
  3250. #endif  
  3251.         if (stat(path, &sb) == -1
  3252.                 || ((sb.st_mode & S_IFMT) != S_IFREG)
  3253.                 || !(sb.st_mode & S_IEXEC)) {
  3254.             if (pvmdebmask & PDMTASK) {
  3255.                 pvmlogprintf("forkexec() stat failed <%s>\n", path);
  3256.             }
  3257.             continue;
  3258.         }
  3259.  
  3260.         if (taskertid) {
  3261.             mp = mesg_new(0);
  3262.             mp->m_tag = SM_STTASK;
  3263.             mp->m_dst = taskertid;
  3264.             pkint(mp, tid);
  3265.             pkint(mp, flags);
  3266.             pkstr(mp, path);
  3267.             for (ac = 1; argv[ac]; ac++) ;
  3268.             pkint(mp, ac);
  3269.             pkstr(mp, path);
  3270.             for (i = 1; i < ac; i++)
  3271.                 pkstr(mp, argv[i]);
  3272.             pkint(mp, nenv + 1);
  3273.             sprintf(buf, "PVMEPID=%d", nextfakepid);
  3274.             pkstr(mp, buf);
  3275.             task_setpid(tp, nextfakepid);
  3276.             if (++nextfakepid > 20000000)
  3277.                 nextfakepid = 10000000;
  3278.             for (i = 0; i < nenv; i++)
  3279.                 pkstr(mp, env[i]);
  3280.             pkint(mp, inst);
  3281.             pkint(mp, hosttotal);
  3282.             pkint(mp, outof);
  3283.             if (pvmdebmask & PDMTASK) {
  3284.                 pvmlogprintf("forkexec() info:: inst %d host %d outof %d\n",
  3285.                             inst, hosttotal, outof);
  3286.             }
  3287.             wp = wait_new(WT_TASKSTART);
  3288.             wp->wa_tid = tid;
  3289.             wp->wa_on = taskertid;
  3290.             mp->m_wid = wp->wa_wid;
  3291.             sendmessage(mp);
  3292.             if (pvmdebmask & PDMTASK) {
  3293.                 pvmlogprintf("forkexec() sent tasker t%x pid %d\n",
  3294.                         tp->t_tid, tp->t_pid);
  3295.             }
  3296.  
  3297.         } else {
  3298. #ifdef    IMA_TITN
  3299.             if (socketpair(AF_UNIX, SOCK_STREAM, 0, pfd) == -1) {
  3300.                 pvmlogperror("forkexec() socketpair");
  3301.                 task_free(tp);
  3302.                 return PvmOutOfRes;
  3303.             }
  3304. #else
  3305.             if (pipe(pfd) == -1) {
  3306.                 pvmlogperror("forkexec() pipe");
  3307.                 task_free(tp);
  3308.                 return PvmOutOfRes;
  3309.             }
  3310. #endif
  3311.  
  3312.     /*
  3313.     * switch runstate to is-task before forking to avoid race.
  3314.     * if we're killed as a task, we don't want to clean up pvmd stuff.
  3315.     */
  3316.             realrunstate = runstate;
  3317.             runstate = PVMDISTASK;
  3318. #if defined(IMA_CSPP) && defined(BALANCED_SPAWN)
  3319.             pid = cnx_sc_fork(CNX_INHERIT_SC, (int) __get_node_id());
  3320. #else
  3321. #ifndef IMA_OS2
  3322.             pid = fork();
  3323. #else
  3324.                         pid = os2_spawn(path,argv,nenv,env,
  3325.                                         flags&PvmTaskDebug?debugger:0);
  3326. #endif
  3327. #endif
  3328.             if (pid)
  3329.                 runstate = realrunstate;
  3330.  
  3331.             if (!pid) {
  3332.  
  3333.     /* close any random fds */
  3334.  
  3335.                 dup2(pfd[1], 1);
  3336.                 dup2(1, 2);
  3337.                 for (i = getdtablesize(); --i > 2; )
  3338.                     (void)close(i);
  3339.     /*
  3340.     * set envars
  3341.     */
  3342.                 while (nenv-- > 0) {
  3343.                     pvmputenv(env[nenv]);
  3344. /*
  3345.                     pvmlogprintf("forkexec() putenv(%s)\n", env[nenv]);
  3346. */
  3347.                 }
  3348.     /*
  3349.     * put expected pid in environment for libpvm in case
  3350.     * the process we exec forks before connecting back to the pvmd
  3351.     */
  3352.                 sprintf(buf, "PVMEPID=%d", getpid());
  3353.                 pvmputenv(buf);
  3354.                 argv[0] = path;
  3355.                 if (flags & PvmTaskDebug) {
  3356.                     char *p;
  3357.  
  3358.                     argv--;
  3359.                     if (p = getenv("PVM_DEBUGGER"))
  3360.                         argv[0] = p;
  3361.                     else
  3362.                         argv[0] = debugger;
  3363.                     execv(argv[0], argv);
  3364.  
  3365.                 } else {
  3366.                     execv(path, argv);
  3367.                 }
  3368.                 exit(1);
  3369.             }
  3370.             if (pid == -1) {
  3371.                 pvmlogperror("forkexec() fork");
  3372.                 (void)close(pfd[0]);
  3373.                 (void)close(pfd[1]);
  3374.                 task_free(tp);
  3375.                 return PvmOutOfRes;
  3376.             }
  3377.             (void)close(pfd[1]);
  3378.  
  3379.             task_setpid(tp, pid);
  3380.             tp->t_out = pfd[0];
  3381.             tp->t_flag |= TF_FORKD;
  3382.  
  3383.             wrk_fds_add(tp->t_out, 1);
  3384.             if (pvmdebmask & PDMTASK) {
  3385.                 pvmlogprintf("forkexec() new task t%x pid %d pfd=%d\n",
  3386.                         tp->t_tid, tp->t_pid, tp->t_out);
  3387.             }
  3388.         }
  3389.  
  3390.         tp->t_a_out = STRALLOC(name);
  3391.         *tpp = tp;
  3392.         return 0;
  3393.     }
  3394.     if (pvmdebmask & PDMTASK) {
  3395.         pvmlogprintf("forkexec() didn't find <%s>\n", name);
  3396.     }
  3397.     task_free(tp);
  3398.     return PvmNoFile;
  3399. }
  3400.  
  3401. #else
  3402.  
  3403. extern char **environ;
  3404. static int nextfakepid = 10000000;        /* XXX fix this */
  3405. int *ptr_nfp = &nextfakepid;
  3406.  
  3407. int
  3408. forkexec(flags, name, argv, nenv, env, tpp)
  3409.     int flags;                /* exec options */
  3410.     char *name;                /* filename */
  3411.     char **argv;            /* arg list (argv[-1] must be there) */
  3412.     int nenv;                /* num of envars */
  3413.     char **env;                /* envars */
  3414.     struct task **tpp;        /* return task context */
  3415. {
  3416.     int tid;                /* task tid */
  3417.     int pid=-1;                /* task pid */
  3418.  
  3419.     struct task *tp;        /* new task context */
  3420.     char *path;
  3421.     struct stat sb;
  3422.     char **ep, **eplist;
  3423.     int i;
  3424.     struct mesg *mp;        /* message to tasker */
  3425.     struct waitc *wp;
  3426.     int ac;
  3427.     char *expected_pid=0;
  3428.     char buf[32];
  3429.     HANDLE hpid;
  3430.     const char *penv=0;
  3431.  
  3432.     SECURITY_ATTRIBUTES saPipe;
  3433.     PROCESS_INFORMATION pi;
  3434.     STARTUPINFO si;  /* for CreateProcess call */
  3435.     char fixedargv[256];
  3436.  
  3437.     static char *nullep[] = { "", 0 };
  3438.  
  3439.     path = (char *) malloc (64 * sizeof(char));
  3440.  
  3441.  
  3442.     if ((tid = tid_new()) < 0) {
  3443.         pvmlogerror("forkexec() out of tids?\n");
  3444.         return PvmOutOfRes;
  3445.     }
  3446.     tp = task_new(tid);
  3447.  
  3448.     /* search for file */     
  3449.  
  3450.     _chdir(getenv("PVM_ROOT"));
  3451.     eplist = CINDEX(name, '/') ? nullep : epaths;
  3452.     make_valid(name);
  3453.  
  3454.     for (ep = eplist; *ep; ep++) {
  3455.     
  3456.         (void)strcpy(path, *ep);
  3457.         if (path[0])
  3458.             (void)strcat(path, "/");
  3459.         
  3460.         (void)strncat(path, name, sizeof(path) - strlen(path) - 1);
  3461.         
  3462.  
  3463.         if (stat(path, &sb) == -1
  3464.                 || ((sb.st_mode & S_IFMT) != S_IFREG)
  3465.                 || !(sb.st_mode & S_IEXEC)) {
  3466.             if (pvmdebmask & PDMTASK) {
  3467.                 pvmlogprintf("forkexec() stat failed <%s>\n", path);
  3468.             }
  3469.             continue;
  3470.         }
  3471.     
  3472.     /* have found the path with executable */
  3473.  
  3474.     
  3475.         argv[0] = path;
  3476.  
  3477.         expected_pid=malloc(64 * sizeof(char));
  3478.         sprintf(expected_pid, "PVMEPID=%d", nextfakepid);
  3479.  
  3480.         penv=(const char*) expected_pid;
  3481.         if (_putenv(penv)) {
  3482.             pvmlogerror("putenv failed !\n");
  3483.             exit(1);
  3484.         }
  3485.         /* concatenate the argv together, glue it */
  3486.  
  3487.         if (argv[0]) {
  3488.             strcpy(fixedargv,argv[0]);
  3489.             strcat(fixedargv," ");
  3490.             for (i=1; argv[i];i++) {
  3491.                 strcat(fixedargv,argv[i]);
  3492.                 strcat(fixedargv," ");
  3493.             }
  3494.             fixedargv[strlen(fixedargv)-1]=0;
  3495.         }
  3496.         if (flags & PvmTaskDebug) {
  3497.             char *pdebug;
  3498.             
  3499.                 if (pdebug = getenv("PVM_DEBUGGER"))
  3500.                     argv[0] = pdebug;
  3501.             
  3502.                     saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
  3503.                     saPipe.lpSecurityDescriptor = NULL;
  3504.                     saPipe.bInheritHandle = FALSE;
  3505.  
  3506.                     memset(&si, 0, sizeof(si));
  3507.                     si.cb = sizeof(si);
  3508.                     pid = CreateProcess(
  3509.                             argv[0],    /* filename */
  3510.                             fixedargv,    /* command line for child */
  3511.                             NULL,    /* process security descriptor */
  3512.                             NULL,    /* thread security descriptor */
  3513.                             FALSE,    /* inherit handles? */
  3514.                             DEBUG_PROCESS,    /* creation flags */
  3515.                             NULL,    /* inherited environment address */
  3516.                             NULL,    /* startup dir */
  3517.                                     /* NULL = start in current */
  3518.                             &si,    /* ptr to startup info (input) */
  3519.                             &pi);    /* ptr to process info (output) */
  3520.         } 
  3521.         else {
  3522.            saPipe.nLength = sizeof(SECURITY_ATTRIBUTES);
  3523.            saPipe.lpSecurityDescriptor = NULL;
  3524.            saPipe.bInheritHandle = FALSE;
  3525.  
  3526.            memset(&si, 0, sizeof(si));
  3527.            si.cb = sizeof(si);
  3528.            pid = CreateProcess(
  3529.                     argv[0],        /* filename */
  3530.                     fixedargv,        /* command line for child */
  3531.                     NULL,            /* process security descriptor */
  3532.                     NULL,            /* thread security descriptor */
  3533.                     FALSE,            /* inherit handles? */
  3534.                     DETACHED_PROCESS,    /* creation flags */
  3535.                     NULL,            /* inherited environment address */
  3536.                     NULL,            /* startup dir */
  3537.                                     /* NULL = start in current */
  3538.                     &si,            /* ptr to startup info (input) */
  3539.                     &pi);            /* ptr to process info (output) */
  3540.         }
  3541.  
  3542.         if (pid == -1) {
  3543.             pvmlogperror("forkexec() _spawnve");
  3544.             task_free(tp);
  3545.             return PvmOutOfRes;
  3546.         }
  3547.         CloseHandle(pi.hThread);
  3548.         task_sethandle(tp,pi.hProcess);
  3549.  
  3550.         task_setpid(tp,nextfakepid);
  3551.         nextfakepid++;
  3552.  
  3553.         tp->t_flag |= TF_FORKD;
  3554.  
  3555.         if (pvmdebmask  & PDMTASK) {
  3556.             pvmlogprintf("forkexec() new task t%x pid %d pfd=%d\n",
  3557.                     tp->t_tid, tp->t_pid, tp->t_out);
  3558.         }
  3559.          
  3560.         tp->t_a_out = STRALLOC(name);
  3561.      
  3562.         *tpp = tp;
  3563.     
  3564.         return 0;
  3565.     }     /* for */
  3566.  
  3567.     if (pvmdebmask  & PDMTASK) {
  3568.         pvmlogprintf("forkexec() didn't find <%s>\n", name);
  3569.     }
  3570.     task_free(tp);
  3571.     return PvmNoFile;
  3572. }        
  3573.  
  3574. /* convenience for pvm programs, just program your executable without */
  3575. /* any .exe appendix. added on WIN32 machines automatically. make it */
  3576. /* valid */
  3577.  
  3578. int make_valid(char *n)
  3579. {
  3580.     char *appendix=".exe";
  3581.     int lenapp=0;
  3582.     char *position=0;
  3583.     int i=strlen(n)-1;
  3584.     int j;
  3585.     lenapp=    strlen(appendix)-1;
  3586.  
  3587.     if ((i= i- lenapp) > 0) {
  3588.  
  3589.         position=n;
  3590.         for (j=0;j<i;j++) position++;
  3591.  
  3592.         /* have to append appendix */
  3593.         if (strncmp(position,appendix,lenapp))
  3594.             strcat(n,appendix);
  3595.     } else strcat(n,appendix);
  3596. }
  3597.  
  3598. #endif
  3599.  
  3600.  
  3601. /*    beprime()
  3602. *
  3603. *    Pvmd[master] becomes pvmd'[master].
  3604. *    Set runstate, make ppnetsock the real netsock, close loclsock.
  3605. */
  3606.  
  3607. beprime()
  3608. {
  3609.     struct htab *htp;
  3610.     struct task *tp;
  3611.     int i;
  3612.  
  3613.     runstate = PVMDPRIME;
  3614.  
  3615.     if ((pvmmyupid = getpid()) == -1) {
  3616.         pvmlogerror("beprime() can't getpid()\n");
  3617.         pvmbailout(0);
  3618.     }
  3619.  
  3620.     myhostpart = 0;
  3621.     pvmmytid = TIDPVMD;
  3622.  
  3623.     htp = ht_new(hosts->ht_local);
  3624.     htp->ht_master = hosts->ht_local;
  3625.     htp->ht_local = 0;
  3626.     ht_insert(htp, hosts->ht_hosts[hosts->ht_local]);
  3627.     ht_insert(htp, hosts->ht_hosts[0]);
  3628.     htp->ht_hosts[htp->ht_master]->hd_txseq
  3629.             = htp->ht_hosts[0]->hd_rxseq;
  3630.     htp->ht_hosts[htp->ht_master]->hd_rxseq
  3631.             = htp->ht_hosts[0]->hd_txseq;
  3632.  
  3633.     oldhosts = hosts;
  3634.     hosts = htp;
  3635.  
  3636. #ifndef NOUNIXDOM
  3637.     loclspath = 0;
  3638. #endif
  3639.     (void)close(loclsock);
  3640.     loclsock = -1;
  3641.     loclsnam = 0;
  3642.     (void)close(netsock);
  3643.     netsock = ppnetsock;
  3644.     ppnetsock = -1;
  3645.  
  3646.     locltasks = 0;
  3647.     task_init();
  3648.  
  3649.     /* close everything but netsock, log_fd and 0, 1, 2 */
  3650.  
  3651.     for (i = getdtablesize(); --i > 2; )
  3652.         if (i != netsock && i != log_fd)
  3653.             (void)close(i);
  3654.  
  3655.     wrk_fds_init();
  3656.     wrk_fds_add(netsock, 1);
  3657.  
  3658.     opq = pk_new(0);
  3659.     opq->pk_tlink = opq->pk_trlink = opq;
  3660.  
  3661.     wdead = 0;
  3662.     rdead = 0;
  3663.  
  3664.     return 0;
  3665. }
  3666.  
  3667.  
  3668. /*    pkt_to_host()
  3669. *
  3670. *    Add data pkt to send queue (txq) for a host.  Consume the pkt.
  3671. *    If data plus header length is greater than host mtu,
  3672. *    refragment into >1 pkts.
  3673. *
  3674. *    We have to pay special attention to the FFSOM packet - make it
  3675. *    shorter so there's room to prepend the message header later.
  3676. *
  3677. *    If send window to host has room, push packet to opq.
  3678. */
  3679.  
  3680. int
  3681. pkt_to_host(hp, pp)
  3682.     struct hostd *hp;
  3683.     struct pkt *pp;
  3684. {
  3685.     int maxl = (hp->hd_mtu < pvmudpmtu ? hp->hd_mtu : pvmudpmtu) - DDFRAGHDR;
  3686.     int llim = pp->pk_flag & FFSOM ? maxl - MSGHDRLEN : maxl;
  3687.  
  3688.     pp->pk_flag = (pp->pk_flag & (FFSOM|FFEOM)) | FFDAT;
  3689.     if (pvmdebmask & PDMPACKET) {
  3690.         pvmlogprintf("pkt_to_host() pkt src t%x dst t%x f %s len %d\n",
  3691.                 pp->pk_src, pp->pk_dst, pkt_flags(pp->pk_flag), pp->pk_len);
  3692.     }
  3693.  
  3694.     if (pp->pk_len <= llim) {
  3695.         LISTPUTBEFORE(hp->hd_txq, pp, pk_link, pk_rlink);
  3696.  
  3697.     } else {
  3698.         struct pkt *pp2;
  3699.         char *cp = pp->pk_dat;
  3700.         int togo;
  3701.         int n;
  3702.         int ff = pp->pk_flag & FFSOM;
  3703.         int fe = pp->pk_flag & FFEOM;
  3704.  
  3705.         for (togo = pp->pk_len; togo > 0; togo -= n) {
  3706.             n = min(togo, llim);
  3707.             if ((pvmdebmask & PDMPACKET) && togo != pp->pk_len) {
  3708.                 pvmlogprintf("pkt_to_host() refrag len %d\n", n);
  3709.             }
  3710. #ifdef    STATISTICS
  3711.             stats.refrag++;
  3712. #endif
  3713.             pp2 = pk_new(0);
  3714.             pp2->pk_src = pp->pk_src;
  3715.             pp2->pk_dst = pp->pk_dst;
  3716.             if (n == togo)
  3717.                 ff |= fe;
  3718.             pp2->pk_flag = ff | FFDAT;
  3719.             ff = 0;
  3720.             llim = maxl;
  3721.             pp2->pk_enc = pp->pk_enc;
  3722.             pp2->pk_tag = pp->pk_tag;
  3723.             pp2->pk_ctx = pp->pk_ctx;
  3724.             pp2->pk_wid = pp->pk_wid;
  3725.             pp2->pk_crc = pp->pk_crc;
  3726.             pp2->pk_buf = pp->pk_buf;
  3727.             pp2->pk_max = pp->pk_max;
  3728.             pp2->pk_dat = cp;
  3729.             pp2->pk_len = n;
  3730.             da_ref(pp->pk_buf);
  3731.             cp += n;
  3732.             LISTPUTBEFORE(hp->hd_txq, pp2, pk_link, pk_rlink);
  3733.         }
  3734.         pk_free(pp);
  3735.     }
  3736.  
  3737.     while (hp->hd_nop < nopax
  3738.     && (hp->hd_txq->pk_link != hp->hd_txq)) {
  3739.         if (pvmdebmask & PDMPACKET) {
  3740.             pvmlogprintf("pkt_to_host() pkt to opq\n");
  3741.         }
  3742.         pp = hp->hd_txq->pk_link;
  3743.         LISTDELETE(pp, pk_link, pk_rlink);
  3744.         TVCLEAR(&pp->pk_rtv);
  3745.         TVXADDY(&pp->pk_rta, &hp->hd_rtt, &hp->hd_rtt);
  3746.         TVCLEAR(&pp->pk_rto);
  3747.         TVCLEAR(&pp->pk_at);
  3748.         pp->pk_nrt = 0;
  3749.         pp->pk_hostd = hp;
  3750.         pp->pk_seq = hp->hd_txseq;
  3751.         hp->hd_txseq = NEXTSEQNUM(hp->hd_txseq);
  3752.         pp->pk_ack = 0;
  3753.         LISTPUTBEFORE(hp->hd_opq, pp, pk_link, pk_rlink);
  3754.         hp->hd_nop++;
  3755.         LISTPUTBEFORE(opq, pp, pk_tlink, pk_trlink);
  3756.     }
  3757.     return 0;
  3758. }
  3759.  
  3760.  
  3761. int
  3762. fin_to_host(hp)
  3763.     struct hostd *hp;
  3764. {
  3765.     struct pkt *pp;
  3766.  
  3767.     if (pvmdebmask & PDMPACKET) {
  3768.         pvmlogprintf("fin_to_host() %s\n", hp->hd_name);
  3769.     }
  3770.     pp = pk_new(DDFRAGHDR);    /* XXX could reref a dummy databuf here */
  3771.     pp->pk_dat += DDFRAGHDR;
  3772.     pp->pk_dst = hp->hd_hostpart | TIDPVMD;
  3773.     pp->pk_src = pvmmytid;
  3774.     pp->pk_flag = FFFIN;
  3775.     TVCLEAR(&pp->pk_rtv);
  3776.     TVXADDY(&pp->pk_rta, &hp->hd_rtt, &hp->hd_rtt);
  3777.     TVCLEAR(&pp->pk_rto);
  3778.     TVCLEAR(&pp->pk_at);
  3779.     pp->pk_nrt = 0;
  3780.     pp->pk_hostd = hp;
  3781.     pp->pk_seq = hp->hd_txseq;
  3782.     hp->hd_txseq = NEXTSEQNUM(hp->hd_txseq);
  3783.     pp->pk_ack = 0;
  3784.     LISTPUTBEFORE(hp->hd_opq, pp, pk_link, pk_rlink);
  3785.     hp->hd_nop++;
  3786.     LISTPUTAFTER(opq, pp, pk_tlink, pk_trlink);
  3787.     return 0;
  3788. }
  3789.  
  3790.  
  3791. int
  3792. finack_to_host(hp)
  3793.     struct hostd *hp;
  3794. {
  3795.     struct pkt *pp;
  3796.  
  3797.     if (pvmdebmask & PDMPACKET) {
  3798.         pvmlogprintf("finack_to_host() %s\n", hp->hd_name);
  3799.     }
  3800.     pp = pk_new(DDFRAGHDR);    /* XXX could reref a dummy databuf here */
  3801.     pp->pk_dat += DDFRAGHDR;
  3802.     pp->pk_dst = hp->hd_hostpart | TIDPVMD;
  3803.     pp->pk_src = pvmmytid;
  3804.     pp->pk_flag = FFFIN|FFACK;
  3805.     TVCLEAR(&pp->pk_rtv);
  3806.     TVCLEAR(&pp->pk_rta);
  3807.     TVCLEAR(&pp->pk_rto);
  3808.     TVCLEAR(&pp->pk_at);
  3809.     pp->pk_nrt = 0;
  3810.     pp->pk_hostd = hp;
  3811.     pp->pk_seq = 0;
  3812.     pp->pk_ack = 0;
  3813.     LISTPUTAFTER(opq, pp, pk_tlink, pk_trlink);
  3814.     return 0;
  3815. }
  3816.  
  3817.  
  3818. /*    pkt_to_task()
  3819. *
  3820. *    Add data pkt to send queue (txq) for a task.  Consume the pkt.
  3821. *    If data plus header length is greater than task mtu,
  3822. *    refragment into >1 pkts.
  3823. */
  3824.  
  3825. int
  3826. pkt_to_task(tp, pp)
  3827.     struct task *tp;
  3828.     struct pkt *pp;
  3829. {
  3830.     if (tp->t_sock >= 0 && (tp->t_flag & TF_CONN) 
  3831. #ifdef SHMEM
  3832.         && !(tp -> t_flag & TF_SHM) /* don't add socket if a shm task */
  3833. #endif
  3834.     )
  3835.         wrk_fds_add(tp->t_sock, 2);
  3836.  
  3837. #if defined(IMA_PGON) || defined(IMA_I860)
  3838.     if (TIDISNODE(pp->pk_dst))
  3839.         mpp_output(tp, pp);
  3840.     else
  3841. #endif
  3842. #ifdef SHMEM
  3843.     if (((tp->t_sock < 0) && (tp->t_flag & TF_SHMCONN))
  3844.         || (tp->t_flag & TF_SHMCONN) )
  3845.         mpp_output(tp, pp);
  3846.     else
  3847. #endif
  3848.  
  3849. #ifdef LocalRefragmentTest
  3850.     if (pp->pk_len + DDFRAGHDR <= pvmudpmtu) {
  3851.         LISTPUTBEFORE(tp->t_txq, pp, pk_link, pk_rlink);
  3852.  
  3853.     } else {
  3854.         struct pkt *pp2;
  3855.         int maxl = pvmudpmtu - DDFRAGHDR;
  3856.         char *cp = pp->pk_dat;
  3857.         int togo;
  3858.         int n;
  3859.         int ff = pp->pk_flag & FFSOM;
  3860.         int fe = pp->pk_flag & FFEOM;
  3861.  
  3862.         for (togo = pp->pk_len; togo > 0; togo -= n) {
  3863.             n = min(togo, maxl);
  3864.             pvmlogprintf("pkt_to_task() refrag len %d\n", n);
  3865.             pp2 = pk_new(0);
  3866.             pp2->pk_src = pp->pk_src;
  3867.             pp2->pk_dst = pp->pk_dst;
  3868.             if (n == togo)
  3869.                 ff |= fe;
  3870.             pp2->pk_flag = ff | FFDAT;
  3871.             ff = 0;
  3872.             pp2->pk_enc = pp->pk_enc;
  3873.             pp2->pk_tag = pp->pk_tag;
  3874.             pp2->pk_ctx = pp->pk_ctx;
  3875.             pp2->pk_wid = pp->pk_wid;
  3876.             pp2->pk_crc = pp->pk_crc;
  3877.             pp2->pk_buf = pp->pk_buf;
  3878.             pp2->pk_max = pp->pk_max;
  3879.             pp2->pk_dat = cp;
  3880.             pp2->pk_len = n;
  3881.             da_ref(pp->pk_buf);
  3882.             cp += n;
  3883.             LISTPUTBEFORE(tp->t_txq, pp2, pk_link, pk_rlink);
  3884.         }
  3885.         pk_free(pp);
  3886.     }
  3887. #else /*LocalRefragmentTest*/
  3888.     {
  3889.     if (pvmdebmask & PDMMESSAGE)
  3890.         pvmlogprintf("pkt_to_task: queueing %x \n", pp->pk_dst);
  3891.     LISTPUTBEFORE(tp->t_txq, pp, pk_link, pk_rlink);
  3892.     }
  3893. #endif /*LocalRefragmentTest*/
  3894.  
  3895.     return 0;
  3896. }
  3897.  
  3898.  
  3899. #ifdef    STATISTICS
  3900. dump_statistics()
  3901. {
  3902.     pvmlogprintf(" select: rdy %d, zero %d, neg %d\n",
  3903.             stats.selrdy, stats.selzer, stats.selneg);
  3904.     pvmlogprintf(" sendto: ok %d, neg %d  recvfrom: ok %d\n",
  3905.             stats.sdok, stats.sdneg, stats.rfok);
  3906.     pvmlogprintf(" read: pos %d, zero %d, neg %d\n",
  3907.             stats.rdok, stats.rdzer, stats.rdneg);
  3908.     pvmlogprintf(" write: ok %d, short %d, zero %d, neg %d\n",
  3909.             stats.wrok, stats.wrshr, stats.wrzer, stats.wrneg);
  3910.     pvmlogprintf(" refrags: %d\n", stats.refrag);
  3911.     pvmlogprintf(" netwk resends: %d\n", stats.netret);
  3912.     return 0;
  3913. }
  3914.  
  3915.  
  3916. reset_statistics()
  3917. {
  3918.     BZERO((char*)&stats, sizeof(stats));
  3919.     return 0;
  3920. }
  3921. #endif    /*STATISTICS*/
  3922.  
  3923.  
  3924. #if defined(IMA_CSPP) && defined(BALANCED_SPAWN)
  3925. static int number_nodes = -1;
  3926. static int number_cpus = -1;
  3927. static cnx_scid_t scid_num;
  3928.  
  3929. static int
  3930. __get_node_id()
  3931. {
  3932.     static int current_node = 0;
  3933.     static int current_cpu = 0;
  3934.  
  3935.     if (number_nodes == -1) {
  3936.         number_nodes = get_number_nodes();
  3937.         number_cpus = get_number_cpus(current_node);
  3938.         goto done;
  3939.     }
  3940.  
  3941.     if (number_nodes == 1) {
  3942.         goto done;
  3943.     }
  3944.  
  3945.     if (current_cpu < (number_cpus - 1) ) {
  3946.         current_cpu++;
  3947.  
  3948.     } else {
  3949.         current_cpu = 0;
  3950.         if (current_node < (number_nodes - 1)) {
  3951.             current_node++;
  3952.             number_cpus = get_number_cpus(current_node);
  3953.         } else {
  3954.             current_node = 0;
  3955.             number_cpus = get_number_cpus(current_node);
  3956.             if (pvmdebmask & PDMTASK) {
  3957.                 pvmlogerror (
  3958.                     "Warning:pvm_spawn restarting process placement on Node 0");
  3959.             }
  3960.         }
  3961.     }
  3962. done:
  3963.     return current_node;
  3964. }
  3965.  
  3966.  
  3967. static cnx_is_scnode_basic_info_data_t sc_info[CNX_MAX_NODES];
  3968.  
  3969. static int
  3970. get_number_nodes()
  3971. {
  3972.     cnx_is_target_data_t target;
  3973.     int ret;
  3974.     cnx_pattributes_t pattr;
  3975.     int val;
  3976.     char errortxt[128];
  3977.  
  3978.     cnx_getpattr(getpid(), CNX_PATTR_SCID, &pattr);
  3979.     scid_num = pattr.pattr_scid;
  3980.     cnx_sysinfo_target_scnode(&target, scid_num, CNX_IS_ALL_NODES);
  3981.     ret = cnx_sysinfo(
  3982.         CNX_IS_SCNODE_BASIC_INFO,
  3983.         (void *) &target,
  3984.         sc_info,
  3985.         CNX_MAX_NODES,
  3986.         CNX_IS_SCNODE_BASIC_INFO_COUNT,
  3987.         (unsigned *) &val);
  3988.  
  3989.     if (ret == -1) {
  3990.         sprintf(errortxt,
  3991.                 "Error calling cnx_sysinfo in %s:line %d errno: %d \n",
  3992.                 __FILE__, __LINE__, errno);
  3993.         pvmlogerror(errortxt);
  3994.         exit (-1);
  3995.     }
  3996.     return val;
  3997. }
  3998.  
  3999. static int
  4000. get_number_cpus(int current_node)
  4001. {
  4002.     return sc_info[current_node].num_cpus;
  4003. }
  4004.  
  4005. #endif /*defined(IMA_CSPP) && defined(BALANCED_SPAWN)*/
  4006.  
  4007.  
  4008. /*    mksocs()
  4009. *
  4010. *    Make UDP sockets netsock and ppnetsock.  Make TCP master socket
  4011. *    loclsock.
  4012. *
  4013. *    Returns 0 if ok,
  4014. *    else 2 if pvmd already running,
  4015. *    else 1.
  4016. */
  4017.  
  4018. int
  4019. mksocs()
  4020. {
  4021.     struct hostd *hp = hosts->ht_hosts[hosts->ht_local];
  4022.     struct hostd *hp0 = hosts->ht_hosts[0];
  4023.     struct sockaddr_in sin;
  4024.     char buf[128];
  4025.     char *sfn;
  4026. #ifndef WIN32
  4027.     int d;
  4028. #else
  4029.     HANDLE d;
  4030.     int e;
  4031. #endif
  4032. #ifndef NOSOCKOPT
  4033.     int bsz;
  4034. #endif
  4035.     char *p;
  4036. #ifdef SOCKLENISUINT
  4037.     size_t oslen;
  4038. #else
  4039.     int oslen;
  4040. #endif
  4041.     int cc;
  4042. #ifndef NOUNIXDOM
  4043.     char spath[LEN_OF_TMP_NAM];    /* local socket path */
  4044.     struct sockaddr_un uns;
  4045. #endif
  4046.  
  4047.     /*
  4048.     * make pvmd-pvmd socket
  4049.     */
  4050.  
  4051.     if ((netsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  4052.         pvmlogperror("mksocs() socket netsock");
  4053.         return 1;
  4054.     }
  4055.  
  4056.     hp->hd_sad.sin_port = 0;
  4057.     if (bind(netsock, (struct sockaddr*)&hp->hd_sad, sizeof(hp->hd_sad)) == -1)
  4058.     {
  4059.         pvmlogperror("mksocs() bind netsock");
  4060.         return 1;
  4061.     }
  4062.     oslen = sizeof(hp->hd_sad);
  4063.     if (getsockname(netsock, (struct sockaddr*)&hp->hd_sad, &oslen) == -1) {
  4064.         pvmlogperror("mksocs() getsockname netsock");
  4065.         return 1;
  4066.     }
  4067.  
  4068.     /*
  4069.     * make pvmd-pvmd' socket
  4070.     */
  4071.  
  4072.     if ((ppnetsock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) {
  4073.         pvmlogperror("mksocs() socket ppnetsock");
  4074.         return 1;
  4075.     }
  4076.  
  4077.     hp0->hd_sad.sin_port = 0;
  4078.     if (bind(ppnetsock, (struct sockaddr*)&hp0->hd_sad, sizeof(hp0->hd_sad))
  4079.     == -1) {
  4080.         pvmlogperror("mksocs() bind ppnetsock");
  4081.         return 1;
  4082.     }
  4083.     oslen = sizeof(hp0->hd_sad);
  4084.     if (getsockname(ppnetsock, (struct sockaddr*)&hp0->hd_sad, &oslen) == -1) {
  4085.         pvmlogperror("mksocs() getsockname ppnetsock");
  4086.         return 1;
  4087.     }
  4088.  
  4089.     /*
  4090.     * make pvmd-local task socket
  4091.     */
  4092.  
  4093. #ifdef NOUNIXDOM
  4094.     if ((loclsock = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  4095.         pvmlogperror("mksocs() socket loclsock");
  4096.         return 1;
  4097.     }
  4098.  
  4099.     /*
  4100.     * first try localhost address (loopback) then regular address
  4101.     * XXX 127.0.0.1 is a hack, we should really gethostbyaddr()
  4102.     */
  4103.  
  4104.     BZERO((char*)&sin, sizeof(sin));
  4105. #ifdef IMA_SP2MPI
  4106.     sin = hp->hd_sad;        /* allow task to connect from a node */
  4107. #else
  4108.     sin.sin_family = AF_INET;
  4109.     sin.sin_addr.s_addr = htonl(0x7f000001);
  4110.     sin.sin_port = 0;
  4111. #endif
  4112.  
  4113.     if (bind(loclsock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
  4114.         sin = hp->hd_sad;
  4115.         if (bind(loclsock, (struct sockaddr*)&sin, sizeof(sin)) == -1) {
  4116.             pvmlogperror("mksocs() bind loclsock");
  4117.             return 1;
  4118.         }
  4119.     }
  4120.     oslen = sizeof(sin);
  4121.     if (getsockname(loclsock, (struct sockaddr*)&sin, &oslen) == -1) {
  4122.         pvmlogperror("mksocs() getsockname loclsock");
  4123.         return 1;
  4124.     }
  4125.  
  4126.     if (listen(loclsock, SOMAXCONN) == -1) {
  4127.         pvmlogperror("mksocs() listen loclsock");
  4128.         return 1;
  4129.     }
  4130.  
  4131. #ifndef NOSOCKOPT
  4132.     bsz = pvmudpmtu * 2;
  4133.     if (setsockopt(netsock, SOL_SOCKET, SO_SNDBUF,
  4134.             (char*)&bsz, sizeof(bsz)) == -1
  4135.     || setsockopt(netsock, SOL_SOCKET, SO_RCVBUF,
  4136.             (char*)&bsz, sizeof(bsz)) == -1
  4137.     || setsockopt(ppnetsock, SOL_SOCKET, SO_SNDBUF,
  4138.             (char*)&bsz, sizeof(bsz)) == -1
  4139.     || setsockopt(ppnetsock, SOL_SOCKET, SO_RCVBUF,
  4140.             (char*)&bsz, sizeof(bsz)) == -1) {
  4141.         pvmlogperror("mksocs() setsockopt");
  4142.         return 1;
  4143.     }
  4144. #endif /*NOSOCKOPT*/
  4145.  
  4146.     p = inadport_hex(&sin);
  4147.  
  4148. #else /*NOUNIXDOM*/
  4149.     if ((loclsock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
  4150.         pvmlogperror("mksocs() socket loclsock");
  4151.         return 1;
  4152.     }
  4153.  
  4154.     BZERO((char*)&uns, sizeof(uns));
  4155.     uns.sun_family = AF_UNIX;
  4156.     spath[0] = 0;
  4157.     (void)TMPNAMFUN(spath);
  4158.     strcpy(uns.sun_path, spath);
  4159. /*
  4160. XXX len?
  4161. */
  4162.  
  4163.     if (bind(loclsock, (struct sockaddr*)&uns, sizeof(uns)) == -1) {
  4164.         pvmlogperror("mksocs() bind loclsock");
  4165.         return 1;
  4166.     }
  4167.  
  4168.     if (listen(loclsock, SOMAXCONN) == -1) {
  4169.         pvmlogperror("mksocs() listen loclsock");
  4170.         return 1;
  4171.     }
  4172.  
  4173.     loclspath = STRALLOC(spath);
  4174.     p = spath;
  4175.  
  4176. #endif /*NOUNIXDOM*/
  4177.  
  4178.     /*
  4179.     * make pvmd-local task socket address file
  4180.     */
  4181.  
  4182.     if (!(sfn = pvmdsockfile())) {
  4183.         pvmlogerror("mksocs() pvmdsockfile() failed\n");
  4184.         pvmbailout(0);
  4185.     }
  4186.  
  4187. #ifndef WIN32
  4188.     if ((d = open(sfn, O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0600)) == -1) {
  4189.         if (errno == EEXIST) {
  4190. #else 
  4191.     if (((HANDLE) d = win32_create_file(sfn, CREATE_NEW))
  4192.             == (HANDLE) -2) {
  4193.         /* this code is for WIN95 */
  4194.         system_loser_win = TRUE;        
  4195.         e = _open(sfn,O_CREAT|O_EXCL|O_WRONLY|O_TRUNC, 0600);
  4196.     }
  4197.     if ((d == (HANDLE) -1) || (e ==-1)) {
  4198.         if (1) {  /* errno == EEXIST */
  4199. #endif
  4200. #ifndef    OVERLOADHOST
  4201.             (void)pvmlogprintf(
  4202.                     "mksocs() %s exists.  pvmd already running?\n", sfn);
  4203.             return 2;
  4204. #endif
  4205.  
  4206.         } else {
  4207.             pvmlogperror(sfn);
  4208.             pvmlogerror("mksocs() can't write address file\n");
  4209.             return 1;
  4210.         }
  4211.     } else {
  4212. #ifndef WIN32
  4213.         cc = write(d, p, strlen(p));
  4214. #else
  4215.         CloseHandle(d);
  4216.         if (!system_loser_win) {
  4217.             if ((d = (HANDLE) win32_open_file(sfn)) == (HANDLE) -1) {
  4218.                 pvmlogprintf("could not open file %s: %d \n",
  4219.                         sfn,GetLastError());
  4220.             return 2;
  4221.             }
  4222.             cc = win32_write_file(d,p,strlen(p));
  4223.         } else
  4224.             /* the win95 case */
  4225.             cc = _write(e,p,strlen(p));
  4226. #endif
  4227.         if (cc != strlen(p)) {
  4228.             if (cc == -1) {
  4229.                 pvmlogperror(sfn);
  4230.                 pvmlogerror("mksocs() can't write address file\n");
  4231.  
  4232.             } else {
  4233.                 (void)pvmlogprintf(
  4234.                         "mksocs() aargh, short write on %s: %d\n",
  4235.                         sfn, cc);
  4236.                 pvmlogerror("mksocs() is the partition full?\n");
  4237.             }
  4238. #ifndef WIN32
  4239.             (void)close(d);
  4240. #else
  4241.             if (d)
  4242.                 CloseHandle(d);
  4243.             if (e)
  4244.                 close(e);
  4245. #endif
  4246.             (void)unlink(sfn);
  4247.             return 1;
  4248.         }
  4249.         loclsnam = STRALLOC(sfn);
  4250. #ifndef WIN32
  4251.         (void)close(d);
  4252. #else
  4253.         if (d)
  4254.             win32_close_file(d);
  4255.         if (e)
  4256.             close(e);
  4257. #endif
  4258.     }
  4259.  
  4260.     /* set PVMSOCK envar */
  4261.  
  4262.     sprintf(buf, "PVMSOCK=%s", p);
  4263.     p = STRALLOC(buf);
  4264.     pvmputenv(p);
  4265.  
  4266.     return 0;
  4267. }
  4268.  
  4269.  
  4270. /*    colonsep()
  4271. *
  4272. *    Break string into substrings on ':' delimiter.
  4273. *    Return null-terminated array of strings, in new malloc'd space.
  4274. *    Modifies the original string.
  4275. */
  4276.  
  4277. char **
  4278. colonsep(s)
  4279.     char *s;    /* the string to break up */
  4280. {
  4281.     char **els;
  4282.     int nel = 2;            /* length of els */
  4283.     char *p, *q;
  4284.  
  4285. #ifdef IMA_OS2
  4286.     for (p = s; p = CINDEX(p, ';'); p++)
  4287. #else
  4288.     for (p = s; p = CINDEX(p, ':'); p++)
  4289. #endif
  4290.         nel++;
  4291.     els = TALLOC(nel, char*, "path");
  4292.  
  4293.     nel = 0;
  4294.     for (p = s; p; p = q) {
  4295. #ifdef IMA_OS2
  4296.         if (q = CINDEX(p, ';'))
  4297. #else
  4298.         if (q = CINDEX(p, ':'))
  4299. #endif
  4300.             *q++ = 0;
  4301.         els[nel++] = p;
  4302.     }
  4303.     els[nel] = 0;
  4304.     return els;
  4305. }
  4306.  
  4307.  
  4308. /*    varsub()
  4309. *
  4310. *    Substitute environment variables into string.
  4311. *    Variables named by $NAME or ${NAME}.
  4312. *    Return string in new malloc'd space.
  4313. */
  4314.  
  4315. char *
  4316. varsub(s)
  4317.     char *s;
  4318. {
  4319.     int rm = 8;        /* length of result string space */
  4320.     char *r;        /* result string */
  4321.     int rl = 0;
  4322.     char *p;
  4323.     char *vn, *vv;
  4324.     char c;
  4325.     int l;
  4326.  
  4327.     r = TALLOC(rm, char, "var");
  4328.     while (*s) {
  4329.         for (p = s; *p && *p != '$'; p++) ;
  4330.         if (l = p - s) {
  4331.             if (rl + l >= rm) {
  4332.                 rm = rl + l + 1;
  4333.                 r = TREALLOC(r, rm, char);
  4334.             }
  4335.             strncpy(r + rl, s, l);
  4336.             rl += l;
  4337.         }
  4338.         s = p++;
  4339.         if (*s == '$') {
  4340.             if (*p == '{')
  4341.                 p++;
  4342.             vn = p;
  4343.             while (isalnum(*p) || *p == '_')
  4344.                 p++;
  4345.             c = *p;
  4346.             *p = 0;
  4347.             vv = getenv(vn);
  4348.             *p = c;
  4349.             if (*p == '}')
  4350.                 p++;
  4351.             if (vv)
  4352.                 l = strlen(vv);
  4353.             else {
  4354.                 vv = s;
  4355.                 l = p - s;
  4356.             }
  4357.             if (l) {
  4358.                 if (rl + l >= rm) {
  4359.                     rm = rl + l + 1;
  4360.                     r = TREALLOC(r, rm, char);
  4361.                 }
  4362.                 strncpy(r + rl, vv, l);
  4363.                 rl += l;
  4364.             }
  4365.             s = p;
  4366.         }
  4367.     }
  4368.     r[rl] = 0;
  4369.     return r;
  4370. }
  4371.  
  4372.  
  4373. /*    crunchzap()
  4374. *
  4375. *    Parse a string into words delimited by <> pairs.
  4376. *    Max number of words is original value of *acp.
  4377. *
  4378. *    Trashes out the original string.
  4379. *    Returns 0 with av[0]..av[*acp - 1] pointing to the words.
  4380. *    Returns 1 if too many words.
  4381. */
  4382.  
  4383. int
  4384. crunchzap(s, acp, av)
  4385.     char *s;        /* the string to parse */
  4386.     int *acp;        /* max words in, ac out */
  4387.     char **av;        /* pointers to args */
  4388. {
  4389.     register int ac;
  4390.     register char *p = s;
  4391.     register int n = *acp;
  4392.  
  4393.     /* separate out words of command */
  4394.  
  4395.     ac = 0;
  4396.     while (*p) {
  4397.         while (*p && *p++ != '<');
  4398.         if (*p) {
  4399.             if (ac >= n) {
  4400.     /* command too long */
  4401.                 *acp = ac;
  4402.                 return 1;
  4403.             }
  4404.             av[ac++] = p;
  4405.             while (*p && *p != '>') p++;
  4406.             if (*p) *p++ = 0;
  4407.         }
  4408.     }
  4409.     *acp = ac;
  4410.     return 0;
  4411. }
  4412.  
  4413.  
  4414. /*    master_config()
  4415. *
  4416. *    Master pvmd.  Config a host table with length 1.
  4417. */
  4418.  
  4419. int
  4420. master_config(hn, argc, argv)
  4421.     char *hn;            /* hostname or null */
  4422.     int argc;
  4423.     char **argv;
  4424. {
  4425.     struct hostent *he;
  4426.     struct hostd *hp;
  4427.     struct hostd *hp2;
  4428.     int i;
  4429.     char *s;
  4430.  
  4431.     if (argc > 2) {
  4432.         pvmlogerror("usage: pvmd3 [-ddebugmask] [-nhostname] [hostfile]\n");
  4433.         pvmbailout(0);
  4434.     }
  4435.     if (argc == 2) {
  4436.         filehosts = readhostfile(argv[1]);
  4437.     }
  4438.     if (pvmdebmask & PDMSTARTUP) {
  4439.         if (filehosts) {
  4440.             pvmlogerror("master_config() host file:\n");
  4441.             ht_dump(filehosts);
  4442.  
  4443.         } else
  4444.             pvmlogerror("master_config() null host file\n");
  4445.     }
  4446.  
  4447.     hosts = ht_new(1);
  4448.     hosts->ht_serial = 1;
  4449.     hosts->ht_master = 1;
  4450.     hosts->ht_cons = 1;
  4451.     hosts->ht_local = 1;
  4452.  
  4453.     hp = hd_new(1);
  4454.     hp->hd_name = STRALLOC(hn);
  4455.     hp->hd_arch = STRALLOC(myarchname);
  4456.     hp->hd_mtu = pvmudpmtu;
  4457.     hp->hd_dsig = pvmmydsig;
  4458.     ht_insert(hosts, hp);
  4459.     hd_unref(hp);
  4460.  
  4461.     hp = hd_new(0);
  4462.     hp->hd_name = STRALLOC("pvmd'");
  4463.     hp->hd_arch = STRALLOC(myarchname);
  4464.     hp->hd_mtu = pvmudpmtu;
  4465.     hp->hd_dsig = pvmmydsig;
  4466.     ht_insert(hosts, hp);
  4467.     hd_unref(hp);
  4468.  
  4469.     /*
  4470.     * get attributes from host file if available
  4471.     */
  4472.  
  4473.     hp = hosts->ht_hosts[1];
  4474.     if (filehosts &&
  4475.             ((hp2 = nametohost(filehosts, hp->hd_name))
  4476.             || (hp2 = filehosts->ht_hosts[0]))) {
  4477.         applydefaults(hp, hp2);
  4478.     }
  4479.  
  4480.     if (!hp->hd_epath) {
  4481.         if ((s = getenv("PVM_PATH")))
  4482.             hp->hd_epath = STRALLOC(s);
  4483.         else
  4484.             hp->hd_epath = STRALLOC(DEFBINDIR);
  4485.     }
  4486.     epaths = colonsep(varsub(hp->hd_epath));
  4487.     if (!hp->hd_bpath)
  4488.         hp->hd_bpath = STRALLOC(DEFDEBUGGER);
  4489.     debugger = varsub(hp->hd_bpath);
  4490.     if (!hp->hd_wdir) {
  4491.         if ((s = getenv("PVM_WD")))
  4492.             hp->hd_wdir = STRALLOC(s);
  4493.         else
  4494.             hp->hd_wdir = STRALLOC(pvmgethome());
  4495.     }
  4496.     s = varsub(hp->hd_wdir);
  4497.     if (chdir(s) == -1)
  4498.         pvmlogperror(s);
  4499.     PVM_FREE(s);
  4500.  
  4501.     if (!(he = gethostbyname(hp->hd_aname ? hp->hd_aname : hp->hd_name))) {
  4502.         pvmlogprintf("master_config() %s: can't gethostbyname\n", hn);
  4503.         pvmbailout(0);
  4504.     }
  4505.  
  4506.     BCOPY(he->h_addr_list[0], (char*)&hp->hd_sad.sin_addr,
  4507.         sizeof(struct in_addr));
  4508.  
  4509.     hp = hosts->ht_hosts[0];
  4510.     BCOPY(he->h_addr_list[0], (char*)&hp->hd_sad.sin_addr,
  4511.         sizeof(struct in_addr));
  4512.  
  4513.     if (pvmdebmask & (PDMHOST|PDMSTARTUP)) {
  4514.         pvmlogerror("master_config() host table:\n");
  4515.         ht_dump(hosts);
  4516.     }
  4517.  
  4518.     if (mksocs())
  4519.         pvmbailout(0);
  4520.  
  4521.  
  4522. #ifndef WIN32
  4523.     /* close everything but our sockets */
  4524.     for (i = getdtablesize(); --i > 2; )
  4525. /* XXX don't like this - hard to maintain */
  4526.         if (i != netsock && i != ppnetsock && i != loclsock && i != log_fd)
  4527.             (void)close(i);
  4528.  
  4529.     /* reopen 0, 1, 2*/
  4530.  
  4531.     (void)open("/dev/null", O_RDONLY, 0);
  4532.     (void)open("/dev/null", O_WRONLY, 0);
  4533.     (void)dup2(1, 2);
  4534. #endif
  4535.  
  4536.     pvmsetlog(2);
  4537.  
  4538.     runstate = PVMDNORMAL;
  4539.     return 0;
  4540. }
  4541.  
  4542.  
  4543. /*    slave_config()
  4544. *
  4545. *    Slave pvmd being started by master.  Trade minimal config info
  4546. *    so we can send packets back and forth.
  4547. */
  4548.  
  4549. int
  4550. slave_config(hn, argc, argv)
  4551.     char *hn;
  4552.     int argc;
  4553.     char **argv;
  4554. {
  4555.     int lh;            /* local host index */
  4556.     int mh;            /* master host index */
  4557.     struct hostd *hp;
  4558.     int i, j;
  4559.     int ac;
  4560.     int ms = 0;        /* manual (humanoid) startup */
  4561. #ifndef WIN32
  4562.     int dof = 1;        /* fork, exit parent (default) */
  4563. #else
  4564.     int dof = 0;
  4565. #endif
  4566.     int bad = 0;
  4567.     char *p;
  4568.     char *s;
  4569.  
  4570.     for (i = j = ac = 1; i < argc; i++) {
  4571.         if (argv[i][0] == '-') {
  4572.             switch (argv[i][1]) {
  4573.  
  4574.             case 'S':
  4575.                 ms = 1;
  4576.                 break;
  4577.  
  4578.             case 'f':
  4579.                 dof = 0;
  4580.                 break;
  4581.  
  4582.             default:
  4583.                 pvmlogprintf("slave_config() unknown switch: %s\n", argv[i]);
  4584.                 bad++;
  4585.             }
  4586.  
  4587.         } else {
  4588.             argv[j++] = argv[i];
  4589.             ac++;
  4590.         }
  4591.     }
  4592.     argc = ac;
  4593.  
  4594.     if (bad || argc != 6) {
  4595.         pvmlogerror("slave_config: bad args\n");
  4596.         pvmbailout(0);
  4597.     }
  4598.  
  4599.     mh = atoi(argv[1]);
  4600.     lh = atoi(argv[4]);
  4601.     hosts = ht_new(1);
  4602.     hosts->ht_serial = 1;
  4603.     hosts->ht_master = mh;
  4604.     hosts->ht_cons = mh;
  4605.     hosts->ht_local = lh;
  4606.  
  4607.     hp = hd_new(mh);
  4608.     hp->hd_name = STRALLOC("?");
  4609.     hex_inadport(argv[2], &hp->hd_sad);
  4610.     hp->hd_mtu = atoi(argv[3]);
  4611.     ht_insert(hosts, hp);
  4612.     hd_unref(hp);
  4613.  
  4614.     hp = hd_new(0);
  4615.     hp->hd_name = STRALLOC("pvmd'");
  4616.     hp->hd_arch = STRALLOC(myarchname);
  4617.     hp->hd_mtu = pvmudpmtu;
  4618.     hp->hd_dsig = pvmmydsig;
  4619.     hex_inadport(argv[5], &hp->hd_sad);
  4620.     ht_insert(hosts, hp);
  4621.     hd_unref(hp);
  4622.  
  4623.     hp = hd_new(lh);
  4624.     hp->hd_name = STRALLOC(hn);
  4625.     hp->hd_arch = STRALLOC(myarchname);
  4626.     hp->hd_mtu = pvmudpmtu;
  4627.     hp->hd_dsig = pvmmydsig;
  4628.     hex_inadport(argv[5], &hp->hd_sad);
  4629.     ht_insert(hosts, hp);
  4630.     hd_unref(hp);
  4631.  
  4632.     if (i = mksocs()) {
  4633.         if (i == 2) {
  4634.             printf("PvmDupHost\n");
  4635.             fflush(stdout);
  4636.         }
  4637.         pvmbailout(0);
  4638.     }
  4639.  
  4640.     printf("ddpro<%d> arch<%s> ip<%s> mtu<%d> dsig<%d>\n",
  4641.         DDPROTOCOL,
  4642.         myarchname,
  4643.         inadport_hex(&hp->hd_sad),
  4644.         pvmudpmtu,
  4645.         pvmmydsig);
  4646.     fflush(stdout);
  4647.  
  4648.     if (!ms)
  4649. #ifndef WIN32
  4650. #ifdef IMA_OS2  
  4651. /* --- */
  4652. #else
  4653.                 (void)read(0, (char*)&i, 1);
  4654. #endif
  4655. #else
  4656.         (void)_read(0, (char*)&i, 1);
  4657. #endif
  4658.  
  4659. #ifndef WIN32
  4660.  
  4661.     if (dof) {
  4662.         if (i = fork()) {
  4663.             if (i == -1)
  4664.                 pvmlogperror("slave_config() fork");
  4665.             exit(0);
  4666.         }
  4667.  
  4668.     /* close everything but our sockets */
  4669.  
  4670.         for (i = getdtablesize(); --i >= 0; )
  4671. /* XXX don't like this - hard to maintain */
  4672.             if (i != netsock && i != loclsock && i != log_fd)
  4673.                 (void)close(i);
  4674.     }
  4675.  
  4676.     /* reopen 0, 1, 2*/
  4677.  
  4678.     (void)open("/dev/null", O_RDONLY, 0);
  4679.     (void)open("/dev/null", O_WRONLY, 0);
  4680.     (void)dup2(1, 2);
  4681.  
  4682. #else
  4683.  
  4684.     fprintf (stderr,"Sorry, no support for WIN32 \n");
  4685.     exit(1);
  4686.  
  4687. #endif
  4688.  
  4689.     pvmsetlog(2);
  4690.  
  4691.     if ((p = getenv("PVM_PATH")))
  4692.         s = STRALLOC(p);
  4693.     else
  4694.         s = STRALLOC(DEFBINDIR);
  4695.     epaths = colonsep(varsub(s));
  4696.     PVM_FREE(s);
  4697.  
  4698.     s = STRALLOC(DEFDEBUGGER);
  4699.     debugger = varsub(s);
  4700.     PVM_FREE(s);
  4701.  
  4702.     if ((s = getenv("PVM_WD")))
  4703.         p = STRALLOC(s);
  4704.     else
  4705.         p = STRALLOC(pvmgethome());
  4706.     s = varsub(p);
  4707.     if (chdir(s) == -1)
  4708.         pvmlogperror(s);
  4709.     PVM_FREE(p);
  4710.     PVM_FREE(s);
  4711.  
  4712.     runstate = PVMDSTARTUP;
  4713.  
  4714.     return 0;
  4715. }
  4716.  
  4717.  
  4718.